summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.xml22
-rw-r--r--core/java/android/view/ViewRoot.java5
-rw-r--r--core/java/android/widget/CursorTreeAdapter.java8
-rw-r--r--core/java/android/widget/SimpleCursorTreeAdapter.java55
-rw-r--r--core/jni/android_app_NativeActivity.cpp171
-rw-r--r--core/jni/android_os_MessageQueue.cpp4
-rw-r--r--core/jni/android_view_Surface.cpp2
-rw-r--r--core/jni/com_google_android_gles_jni_EGLImpl.cpp3
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_phone_call_bluetooth.pngbin1263 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_phone_call_ringing.pngbin1239 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_vp_phone_call_bluetooth.pngbin1263 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_phone_call_bluetooth.pngbin815 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_phone_call_ringing.pngbin773 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_vp_phone_call_bluetooth.pngbin815 -> 0 bytes
-rw-r--r--core/res/res/values/public.xml1
-rw-r--r--docs/html/sdk/download.jd4
-rw-r--r--include/android_runtime/android_app_NativeActivity.h35
-rw-r--r--include/android_runtime/android_view_Surface.h (renamed from core/jni/android_view_Surface.h)0
-rw-r--r--include/media/EffectBassBoostApi.h42
-rw-r--r--include/media/EffectEnvironmentalReverbApi.h (renamed from include/media/EffectReverbApi.h)27
-rw-r--r--include/media/EffectPresetReverbApi.h54
-rw-r--r--include/media/EffectVirtualizerApi.h42
-rw-r--r--include/media/MediaRecorderBase.h1
-rw-r--r--include/media/PVMediaRecorder.h1
-rw-r--r--include/ui/Rect.h33
-rw-r--r--include/utils/PollLoop.h42
-rw-r--r--libs/ui/InputDispatcher.cpp2
-rw-r--r--libs/ui/Rect.cpp8
-rw-r--r--libs/utils/PollLoop.cpp93
-rw-r--r--libs/utils/tests/PollLoop_test.cpp78
-rw-r--r--media/java/android/media/BassBoost.java213
-rw-r--r--media/java/android/media/EnvironmentalReverb.java504
-rw-r--r--media/java/android/media/Equalizer.java443
-rw-r--r--media/java/android/media/PresetReverb.java219
-rw-r--r--media/java/android/media/Virtualizer.java214
-rw-r--r--media/jni/audioeffect/android_media_AudioEffect.cpp4
-rw-r--r--media/libeffects/EffectReverb.c1145
-rw-r--r--media/libeffects/EffectReverb.h7
-rw-r--r--media/libmedia/AudioEffect.cpp4
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp16
-rw-r--r--media/libmediaplayerservice/MediaRecorderClient.cpp7
-rw-r--r--media/libmediaplayerservice/MediaRecorderClient.h19
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.cpp60
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.h1
-rw-r--r--media/libstagefright/OMXCodec.cpp2
-rw-r--r--media/libstagefright/codecs/aacdec/AACDecoder.cpp106
-rw-r--r--media/libstagefright/include/AACDecoder.h4
-rw-r--r--native/android/Android.mk7
-rw-r--r--native/android/activity.cpp0
-rw-r--r--native/android/input.cpp4
-rw-r--r--native/android/looper.cpp31
-rw-r--r--native/android/native_activity.cpp31
-rw-r--r--native/android/native_window.cpp58
-rw-r--r--native/glue/threaded_app/Android.mk18
-rw-r--r--native/glue/threaded_app/threaded_app.c279
-rw-r--r--native/include/android/input.h5
-rw-r--r--native/include/android/looper.h134
-rw-r--r--native/include/android/native_activity.h5
-rw-r--r--native/include/android/native_window.h43
-rw-r--r--native/include/android/native_window_jni.h40
-rw-r--r--native/include/android/rect.h36
-rw-r--r--native/include/android/window.h58
-rw-r--r--native/include/android_glue/threaded_app.h165
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java32
-rw-r--r--test-runner/src/android/test/InstrumentationTestRunner.java22
-rw-r--r--test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java44
66 files changed, 3814 insertions, 899 deletions
diff --git a/api/current.xml b/api/current.xml
index 64dd3a8..7a86d05 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -4717,6 +4717,17 @@
visibility="public"
>
</field>
+<field name="immersive"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843457"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="inAnimation"
type="int"
transient="false"
@@ -5916,17 +5927,6 @@
visibility="public"
>
</field>
-<field name="kraken_resource_pad64"
- type="int"
- transient="false"
- volatile="false"
- value="16843457"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="kraken_resource_pad7"
type="int"
transient="false"
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index e980b17..fb45971 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -452,6 +452,7 @@ public final class ViewRoot extends Handler implements ViewParent,
((RootViewSurfaceTaker)view).willYouTakeTheSurface();
if (mSurfaceHolderCallback != null) {
mSurfaceHolder = new TakenSurfaceHolder();
+ mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
}
}
Resources resources = mView.getContext().getResources();
@@ -754,7 +755,7 @@ public final class ViewRoot extends Handler implements ViewParent,
// object is not initialized to its backing store, but soon it
// will be (assuming the window is visible).
attachInfo.mSurface = mSurface;
- attachInfo.mTranslucentWindow = lp.format != PixelFormat.OPAQUE;
+ attachInfo.mTranslucentWindow = PixelFormat.formatHasAlpha(lp.format);
attachInfo.mHasWindowFocus = false;
attachInfo.mWindowVisibility = viewVisibility;
attachInfo.mRecomputeGlobalAttributes = false;
@@ -926,8 +927,6 @@ public final class ViewRoot extends Handler implements ViewParent,
if (mSurfaceHolder != null) {
mSurfaceHolder.mSurfaceLock.lock();
mDrawingAllowed = true;
- lp.format = mSurfaceHolder.getRequestedFormat();
- lp.type = mSurfaceHolder.getRequestedType();
}
boolean initialized = false;
diff --git a/core/java/android/widget/CursorTreeAdapter.java b/core/java/android/widget/CursorTreeAdapter.java
index 7b9b7bd..3fadf4c 100644
--- a/core/java/android/widget/CursorTreeAdapter.java
+++ b/core/java/android/widget/CursorTreeAdapter.java
@@ -134,14 +134,16 @@ public abstract class CursorTreeAdapter extends BaseExpandableListAdapter implem
/**
* Sets the group Cursor.
*
- * @param cursor The Cursor to set for the group.
+ * @param cursor The Cursor to set for the group. If there is an existing cursor
+ * it will be closed.
*/
public void setGroupCursor(Cursor cursor) {
mGroupCursorHelper.changeCursor(cursor, false);
}
/**
- * Sets the children Cursor for a particular group.
+ * Sets the children Cursor for a particular group. If there is an existing cursor
+ * it will be closed.
* <p>
* This is useful when asynchronously querying to prevent blocking the UI.
*
@@ -476,7 +478,7 @@ public abstract class CursorTreeAdapter extends BaseExpandableListAdapter implem
mCursor.unregisterContentObserver(mContentObserver);
mCursor.unregisterDataSetObserver(mDataSetObserver);
- mCursor.deactivate();
+ mCursor.close();
mCursor = null;
}
diff --git a/core/java/android/widget/SimpleCursorTreeAdapter.java b/core/java/android/widget/SimpleCursorTreeAdapter.java
index a1c65f0..a033542 100644
--- a/core/java/android/widget/SimpleCursorTreeAdapter.java
+++ b/core/java/android/widget/SimpleCursorTreeAdapter.java
@@ -38,6 +38,10 @@ import android.view.View;
* binding can be found, an {@link IllegalStateException} is thrown.
*/
public abstract class SimpleCursorTreeAdapter extends ResourceCursorTreeAdapter {
+
+ /** The name of the columns that contain the data to display for a group. */
+ private String[] mGroupFromNames;
+
/** The indices of columns that contain data to display for a group. */
private int[] mGroupFrom;
/**
@@ -46,6 +50,9 @@ public abstract class SimpleCursorTreeAdapter extends ResourceCursorTreeAdapter
*/
private int[] mGroupTo;
+ /** The name of the columns that contain the data to display for a child. */
+ private String[] mChildFromNames;
+
/** The indices of columns that contain data to display for a child. */
private int[] mChildFrom;
/**
@@ -171,38 +178,12 @@ public abstract class SimpleCursorTreeAdapter extends ResourceCursorTreeAdapter
private void init(String[] groupFromNames, int[] groupTo, String[] childFromNames,
int[] childTo) {
+
+ mGroupFromNames = groupFromNames;
mGroupTo = groupTo;
+ mChildFromNames = childFromNames;
mChildTo = childTo;
-
- // Get the group cursor column indices, the child cursor column indices will come
- // when needed
- initGroupFromColumns(groupFromNames);
-
- // Get a temporary child cursor to init the column indices
- if (getGroupCount() > 0) {
- MyCursorHelper tmpCursorHelper = getChildrenCursorHelper(0, true);
- if (tmpCursorHelper != null) {
- initChildrenFromColumns(childFromNames, tmpCursorHelper.getCursor());
- deactivateChildrenCursorHelper(0);
- }
- }
- }
-
- private void initFromColumns(Cursor cursor, String[] fromColumnNames, int[] fromColumns) {
- for (int i = fromColumnNames.length - 1; i >= 0; i--) {
- fromColumns[i] = cursor.getColumnIndexOrThrow(fromColumnNames[i]);
- }
- }
-
- private void initGroupFromColumns(String[] groupFromNames) {
- mGroupFrom = new int[groupFromNames.length];
- initFromColumns(mGroupCursorHelper.getCursor(), groupFromNames, mGroupFrom);
- }
-
- private void initChildrenFromColumns(String[] childFromNames, Cursor childCursor) {
- mChildFrom = new int[childFromNames.length];
- initFromColumns(childCursor, childFromNames, mChildFrom);
}
/**
@@ -257,13 +238,29 @@ public abstract class SimpleCursorTreeAdapter extends ResourceCursorTreeAdapter
}
}
+ private void initFromColumns(Cursor cursor, String[] fromColumnNames, int[] fromColumns) {
+ for (int i = fromColumnNames.length - 1; i >= 0; i--) {
+ fromColumns[i] = cursor.getColumnIndexOrThrow(fromColumnNames[i]);
+ }
+ }
+
@Override
protected void bindChildView(View view, Context context, Cursor cursor, boolean isLastChild) {
+ if (mChildFrom == null) {
+ mChildFrom = new int[mChildFromNames.length];
+ initFromColumns(cursor, mChildFromNames, mChildFrom);
+ }
+
bindView(view, context, cursor, mChildFrom, mChildTo);
}
@Override
protected void bindGroupView(View view, Context context, Cursor cursor, boolean isExpanded) {
+ if (mGroupFrom == null) {
+ mGroupFrom = new int[mGroupFromNames.length];
+ initFromColumns(cursor, mGroupFromNames, mGroupFrom);
+ }
+
bindView(view, context, cursor, mGroupFrom, mGroupTo);
}
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index af61b80..54a9c2a 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -21,7 +21,8 @@
#include <dlfcn.h>
#include <android_runtime/AndroidRuntime.h>
-#include <android/native_activity.h>
+#include <android_runtime/android_view_Surface.h>
+#include <android_runtime/android_app_NativeActivity.h>
#include <surfaceflinger/Surface.h>
#include <ui/egl/android_natives.h>
#include <ui/InputTransport.h>
@@ -31,7 +32,6 @@
#include "android_os_MessageQueue.h"
#include "android_view_InputChannel.h"
#include "android_view_KeyEvent.h"
-#include "android_view_Surface.h"
namespace android
{
@@ -46,6 +46,48 @@ static struct {
// ------------------------------------------------------------------------
+struct ActivityWork {
+ int32_t cmd;
+ int32_t arg1;
+ int32_t arg2;
+};
+
+enum {
+ CMD_DEF_KEY = 1,
+ CMD_SET_WINDOW_FORMAT,
+ CMD_SET_WINDOW_FLAGS,
+};
+
+static void write_work(int fd, int32_t cmd, int32_t arg1=0, int32_t arg2=0) {
+ ActivityWork work;
+ work.cmd = cmd;
+ work.arg1 = arg1;
+ work.arg2 = arg2;
+
+restart:
+ int res = write(fd, &work, sizeof(work));
+ if (res < 0 && errno == EINTR) {
+ goto restart;
+ }
+
+ if (res == sizeof(work)) return;
+
+ if (res < 0) LOGW("Failed writing to work fd: %s", strerror(errno));
+ else LOGW("Truncated writing to work fd: %d", res);
+}
+
+static bool read_work(int fd, ActivityWork* outWork) {
+ int res = read(fd, outWork, sizeof(ActivityWork));
+ // no need to worry about EINTR, poll loop will just come back again.
+ if (res == sizeof(ActivityWork)) return true;
+
+ if (res < 0) LOGW("Failed reading work fd: %s", strerror(errno));
+ else LOGW("Truncated reading work fd: %d", res);
+ return false;
+}
+
+// ------------------------------------------------------------------------
+
/*
* Specialized input queue that allows unhandled key events to be dispatched
* back to the native activity's Java framework code.
@@ -59,8 +101,7 @@ struct MyInputQueue : AInputQueue {
mLock.lock();
LOGI("Default key: pending=%d write=%d\n", mPendingKeys.size(), mWorkWrite);
if (mPendingKeys.size() <= 0 && mWorkWrite >= 0) {
- int8_t cmd = 1;
- write(mWorkWrite, &cmd, sizeof(cmd));
+ write_work(mWorkWrite, CMD_DEF_KEY);
}
mPendingKeys.add(keyEvent);
mLock.unlock();
@@ -90,9 +131,9 @@ struct MyInputQueue : AInputQueue {
/*
* Native state for interacting with the NativeActivity class.
*/
-struct NativeCode {
+struct NativeCode : public ANativeActivity {
NativeCode(void* _dlhandle, ANativeActivity_createFunc* _createFunc) {
- memset(&activity, sizeof(activity), 0);
+ memset((ANativeActivity*)this, sizeof(ANativeActivity), 0);
memset(&callbacks, sizeof(callbacks), 0);
dlhandle = _dlhandle;
createActivityFunc = _createFunc;
@@ -103,8 +144,11 @@ struct NativeCode {
}
~NativeCode() {
- if (activity.env != NULL && activity.clazz != NULL) {
- activity.env->DeleteGlobalRef(activity.clazz);
+ if (callbacks.onDestroy != NULL) {
+ callbacks.onDestroy(this);
+ }
+ if (env != NULL && clazz != NULL) {
+ env->DeleteGlobalRef(clazz);
}
if (pollLoop != NULL && mainWorkRead >= 0) {
pollLoop->removeCallback(mainWorkRead);
@@ -114,9 +158,6 @@ struct NativeCode {
}
setSurface(NULL);
setInputChannel(NULL);
- if (callbacks.onDestroy != NULL) {
- callbacks.onDestroy(&activity);
- }
if (mainWorkRead >= 0) close(mainWorkRead);
if (mainWorkWrite >= 0) close(mainWorkWrite);
if (dlhandle != NULL) {
@@ -129,7 +170,7 @@ struct NativeCode {
void setSurface(jobject _surface) {
if (_surface != NULL) {
- nativeWindow = android_Surface_getNativeWindow(activity.env, _surface);
+ nativeWindow = android_Surface_getNativeWindow(env, _surface);
} else {
nativeWindow = NULL;
}
@@ -138,14 +179,14 @@ struct NativeCode {
status_t setInputChannel(jobject _channel) {
if (inputChannel != NULL) {
delete nativeInputQueue;
- activity.env->DeleteGlobalRef(inputChannel);
+ env->DeleteGlobalRef(inputChannel);
}
inputChannel = NULL;
nativeInputQueue = NULL;
if (_channel != NULL) {
- inputChannel = activity.env->NewGlobalRef(_channel);
+ inputChannel = env->NewGlobalRef(_channel);
sp<InputChannel> ic =
- android_view_InputChannel_getInputChannel(activity.env, _channel);
+ android_view_InputChannel_getInputChannel(env, _channel);
if (ic != NULL) {
nativeInputQueue = new MyInputQueue(ic, mainWorkWrite);
if (nativeInputQueue->getConsumer().initialize() != android::OK) {
@@ -160,7 +201,6 @@ struct NativeCode {
return OK;
}
- ANativeActivity activity;
ANativeActivityCallbacks callbacks;
void* dlhandle;
@@ -179,6 +219,18 @@ struct NativeCode {
sp<PollLoop> pollLoop;
};
+void android_NativeActivity_setWindowFormat(
+ ANativeActivity* activity, int32_t format) {
+ NativeCode* code = static_cast<NativeCode*>(activity);
+ write_work(code->mainWorkWrite, CMD_SET_WINDOW_FORMAT, format);
+}
+
+void android_NativeActivity_setWindowFlags(
+ ANativeActivity* activity, int32_t values, int32_t mask) {
+ NativeCode* code = static_cast<NativeCode*>(activity);
+ write_work(code->mainWorkWrite, CMD_SET_WINDOW_FLAGS, values, mask);
+}
+
// ------------------------------------------------------------------------
/*
@@ -186,19 +238,40 @@ struct NativeCode {
*/
static bool mainWorkCallback(int fd, int events, void* data) {
NativeCode* code = (NativeCode*)data;
- if ((events & POLLIN) != 0) {
- KeyEvent* keyEvent;
- while ((keyEvent=code->nativeInputQueue->getNextEvent()) != NULL) {
- jobject inputEventObj = android_view_KeyEvent_fromNative(
- code->activity.env, keyEvent);
- code->activity.env->CallVoidMethod(code->activity.clazz,
- gNativeActivityClassInfo.dispatchUnhandledKeyEvent, inputEventObj);
- int32_t res = code->nativeInputQueue->getConsumer().sendFinishedSignal();
- if (res != OK) {
- LOGW("Failed to send finished signal on channel '%s'. status=%d",
- code->nativeInputQueue->getConsumer().getChannel()->getName().string(), res);
+ if ((events & POLLIN) == 0) {
+ return true;
+ }
+
+ ActivityWork work;
+ if (!read_work(code->mainWorkRead, &work)) {
+ return true;
+ }
+ switch (work.cmd) {
+ case CMD_DEF_KEY: {
+ KeyEvent* keyEvent;
+ while ((keyEvent=code->nativeInputQueue->getNextEvent()) != NULL) {
+ jobject inputEventObj = android_view_KeyEvent_fromNative(
+ code->env, keyEvent);
+ code->env->CallVoidMethod(code->clazz,
+ gNativeActivityClassInfo.dispatchUnhandledKeyEvent, inputEventObj);
+ int32_t res = code->nativeInputQueue->getConsumer().sendFinishedSignal();
+ if (res != OK) {
+ LOGW("Failed to send finished signal on channel '%s'. status=%d",
+ code->nativeInputQueue->getConsumer().getChannel()->getName().string(), res);
+ }
}
- }
+ } break;
+ case CMD_SET_WINDOW_FORMAT: {
+ code->env->CallVoidMethod(code->clazz,
+ gNativeActivityClassInfo.setWindowFormat, work.arg1);
+ } break;
+ case CMD_SET_WINDOW_FLAGS: {
+ code->env->CallVoidMethod(code->clazz,
+ gNativeActivityClassInfo.setWindowFlags, work.arg1, work.arg2);
+ } break;
+ default:
+ LOGW("Unknown work command: %d", work.cmd);
+ break;
}
return true;
@@ -243,28 +316,28 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQ
code->mainWorkWrite = msgpipe[1];
code->pollLoop->setCallback(code->mainWorkRead, POLLIN, mainWorkCallback, code);
- code->activity.callbacks = &code->callbacks;
- if (env->GetJavaVM(&code->activity.vm) < 0) {
+ code->ANativeActivity::callbacks = &code->callbacks;
+ if (env->GetJavaVM(&code->vm) < 0) {
LOGW("NativeActivity GetJavaVM failed");
delete code;
return 0;
}
- code->activity.env = env;
- code->activity.clazz = env->NewGlobalRef(clazz);
+ code->env = env;
+ code->clazz = env->NewGlobalRef(clazz);
const char* dirStr = env->GetStringUTFChars(internalDataDir, NULL);
code->internalDataPath = dirStr;
- code->activity.internalDataPath = code->internalDataPath.string();
+ code->internalDataPath = code->internalDataPath.string();
env->ReleaseStringUTFChars(path, dirStr);
dirStr = env->GetStringUTFChars(externalDataDir, NULL);
code->externalDataPath = dirStr;
- code->activity.externalDataPath = code->externalDataPath.string();
+ code->externalDataPath = code->externalDataPath.string();
env->ReleaseStringUTFChars(path, dirStr);
- code->activity.sdkVersion = sdkVersion;
+ code->sdkVersion = sdkVersion;
- code->createActivityFunc(&code->activity, NULL, 0);
+ code->createActivityFunc(code, NULL, 0);
}
return (jint)code;
@@ -285,7 +358,7 @@ onStart_native(JNIEnv* env, jobject clazz, jint handle)
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
if (code->callbacks.onStart != NULL) {
- code->callbacks.onStart(&code->activity);
+ code->callbacks.onStart(code);
}
}
}
@@ -296,7 +369,7 @@ onResume_native(JNIEnv* env, jobject clazz, jint handle)
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
if (code->callbacks.onResume != NULL) {
- code->callbacks.onResume(&code->activity);
+ code->callbacks.onResume(code);
}
}
}
@@ -308,7 +381,7 @@ onSaveInstanceState_native(JNIEnv* env, jobject clazz, jint handle)
NativeCode* code = (NativeCode*)handle;
if (code->callbacks.onSaveInstanceState != NULL) {
size_t len = 0;
- code->callbacks.onSaveInstanceState(&code->activity, &len);
+ code->callbacks.onSaveInstanceState(code, &len);
}
}
}
@@ -319,7 +392,7 @@ onPause_native(JNIEnv* env, jobject clazz, jint handle)
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
if (code->callbacks.onPause != NULL) {
- code->callbacks.onPause(&code->activity);
+ code->callbacks.onPause(code);
}
}
}
@@ -330,7 +403,7 @@ onStop_native(JNIEnv* env, jobject clazz, jint handle)
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
if (code->callbacks.onStop != NULL) {
- code->callbacks.onStop(&code->activity);
+ code->callbacks.onStop(code);
}
}
}
@@ -341,7 +414,7 @@ onLowMemory_native(JNIEnv* env, jobject clazz, jint handle)
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
if (code->callbacks.onLowMemory != NULL) {
- code->callbacks.onLowMemory(&code->activity);
+ code->callbacks.onLowMemory(code);
}
}
}
@@ -352,7 +425,7 @@ onWindowFocusChanged_native(JNIEnv* env, jobject clazz, jint handle, jboolean fo
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
if (code->callbacks.onWindowFocusChanged != NULL) {
- code->callbacks.onWindowFocusChanged(&code->activity, focused ? 1 : 0);
+ code->callbacks.onWindowFocusChanged(code, focused ? 1 : 0);
}
}
}
@@ -364,7 +437,7 @@ onSurfaceCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject surface
NativeCode* code = (NativeCode*)handle;
code->setSurface(surface);
if (code->nativeWindow != NULL && code->callbacks.onNativeWindowCreated != NULL) {
- code->callbacks.onNativeWindowCreated(&code->activity,
+ code->callbacks.onNativeWindowCreated(code,
code->nativeWindow.get());
}
}
@@ -380,11 +453,11 @@ onSurfaceChanged_native(JNIEnv* env, jobject clazz, jint handle, jobject surface
code->setSurface(surface);
if (oldNativeWindow != code->nativeWindow) {
if (oldNativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) {
- code->callbacks.onNativeWindowDestroyed(&code->activity,
+ code->callbacks.onNativeWindowDestroyed(code,
oldNativeWindow.get());
}
if (code->nativeWindow != NULL && code->callbacks.onNativeWindowCreated != NULL) {
- code->callbacks.onNativeWindowCreated(&code->activity,
+ code->callbacks.onNativeWindowCreated(code,
code->nativeWindow.get());
}
}
@@ -397,7 +470,7 @@ onSurfaceDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject surfa
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
if (code->nativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) {
- code->callbacks.onNativeWindowDestroyed(&code->activity,
+ code->callbacks.onNativeWindowDestroyed(code,
code->nativeWindow.get());
}
code->setSurface(NULL);
@@ -416,7 +489,7 @@ onInputChannelCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject ch
return;
}
if (code->callbacks.onInputQueueCreated != NULL) {
- code->callbacks.onInputQueueCreated(&code->activity,
+ code->callbacks.onInputQueueCreated(code,
code->nativeInputQueue);
}
}
@@ -429,7 +502,7 @@ onInputChannelDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject
NativeCode* code = (NativeCode*)handle;
if (code->nativeInputQueue != NULL
&& code->callbacks.onInputQueueDestroyed != NULL) {
- code->callbacks.onInputQueueDestroyed(&code->activity,
+ code->callbacks.onInputQueueDestroyed(code,
code->nativeInputQueue);
}
code->setInputChannel(NULL);
diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp
index 961f806..847b5a5 100644
--- a/core/jni/android_os_MessageQueue.cpp
+++ b/core/jni/android_os_MessageQueue.cpp
@@ -53,7 +53,7 @@ private:
NativeMessageQueue::NativeMessageQueue() {
mPollLoop = PollLoop::getForThread();
if (mPollLoop == NULL) {
- mPollLoop = new PollLoop();
+ mPollLoop = new PollLoop(false);
PollLoop::setForThread(mPollLoop);
}
}
@@ -62,7 +62,7 @@ NativeMessageQueue::~NativeMessageQueue() {
}
bool NativeMessageQueue::pollOnce(int timeoutMillis) {
- return mPollLoop->pollOnce(timeoutMillis);
+ return mPollLoop->pollOnce(timeoutMillis) != PollLoop::POLL_TIMEOUT;
}
void NativeMessageQueue::wake() {
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index a82abc9..7305032 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -33,7 +33,7 @@
#include "jni.h"
#include <android_runtime/AndroidRuntime.h>
-#include "android_view_Surface.h"
+#include <android_runtime/android_view_Surface.h>
#include <utils/misc.h>
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 866c038..941ed63 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -16,6 +16,7 @@
*/
#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/android_view_Surface.h>
#include <utils/misc.h>
#include <EGL/egl.h>
@@ -25,8 +26,6 @@
#include <SkBitmap.h>
#include <SkPixelRef.h>
-#include "android_view_Surface.h"
-
namespace android {
static jclass gDisplay_class;
diff --git a/core/res/res/drawable-hdpi/stat_sys_phone_call_bluetooth.png b/core/res/res/drawable-hdpi/stat_sys_phone_call_bluetooth.png
deleted file mode 100644
index 2d13237..0000000
--- a/core/res/res/drawable-hdpi/stat_sys_phone_call_bluetooth.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_phone_call_ringing.png b/core/res/res/drawable-hdpi/stat_sys_phone_call_ringing.png
deleted file mode 100644
index 950713b..0000000
--- a/core/res/res/drawable-hdpi/stat_sys_phone_call_ringing.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_vp_phone_call_bluetooth.png b/core/res/res/drawable-hdpi/stat_sys_vp_phone_call_bluetooth.png
deleted file mode 100644
index 2d13237..0000000
--- a/core/res/res/drawable-hdpi/stat_sys_vp_phone_call_bluetooth.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_phone_call_bluetooth.png b/core/res/res/drawable-mdpi/stat_sys_phone_call_bluetooth.png
deleted file mode 100644
index 7abfd19..0000000
--- a/core/res/res/drawable-mdpi/stat_sys_phone_call_bluetooth.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_phone_call_ringing.png b/core/res/res/drawable-mdpi/stat_sys_phone_call_ringing.png
deleted file mode 100644
index c44d062..0000000
--- a/core/res/res/drawable-mdpi/stat_sys_phone_call_ringing.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_vp_phone_call_bluetooth.png b/core/res/res/drawable-mdpi/stat_sys_vp_phone_call_bluetooth.png
deleted file mode 100644
index 7abfd19..0000000
--- a/core/res/res/drawable-mdpi/stat_sys_vp_phone_call_bluetooth.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 27cb763..6c13da6 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1246,6 +1246,7 @@
<public type="attr" name="logo" id="0x010102be" />
<public type="attr" name="xlargeScreens" id="0x010102bf" />
<public type="attr" name="heavyWeight" id="0x010102c0" />
+ <public type="attr" name="immersive" id="0x010102c1" />
<public-padding type="attr" name="kraken_resource_pad" end="0x01010300" />
<public-padding type="id" name="kraken_resource_pad" end="0x01020040" />
diff --git a/docs/html/sdk/download.jd b/docs/html/sdk/download.jd
new file mode 100644
index 0000000..81b4ff6
--- /dev/null
+++ b/docs/html/sdk/download.jd
@@ -0,0 +1,4 @@
+sdk.redirect=true
+
+@jd:body
+
diff --git a/include/android_runtime/android_app_NativeActivity.h b/include/android_runtime/android_app_NativeActivity.h
new file mode 100644
index 0000000..f808328
--- /dev/null
+++ b/include/android_runtime/android_app_NativeActivity.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_APP_NATIVEACTIVITY_H
+#define _ANDROID_APP_NATIVEACTIVITY_H
+
+#include <android/native_activity.h>
+
+#include "jni.h"
+
+namespace android {
+
+extern void android_NativeActivity_setWindowFormat(
+ ANativeActivity* activity, int32_t format);
+
+extern void android_NativeActivity_setWindowFlags(
+ ANativeActivity* activity, int32_t values, int32_t mask);
+
+
+} // namespace android
+
+#endif // _ANDROID_APP_NATIVEACTIVITY_H
diff --git a/core/jni/android_view_Surface.h b/include/android_runtime/android_view_Surface.h
index c37932e..c37932e 100644
--- a/core/jni/android_view_Surface.h
+++ b/include/android_runtime/android_view_Surface.h
diff --git a/include/media/EffectBassBoostApi.h b/include/media/EffectBassBoostApi.h
new file mode 100644
index 0000000..b24a5f4
--- /dev/null
+++ b/include/media/EffectBassBoostApi.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_EFFECTBASSBOOSTAPI_H_
+#define ANDROID_EFFECTBASSBOOSTAPI_H_
+
+#include <media/EffectApi.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// TODO: include OpenSLES_IID.h instead
+static const effect_uuid_t SL_IID_BASSBOOST_ = { 0x0634f220, 0xddd4, 0x11db, 0xa0fc, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+const effect_uuid_t * const SL_IID_BASSBOOST = &SL_IID_BASSBOOST_;
+
+/* enumerated parameter settings for BassBoost effect */
+typedef enum
+{
+ BASSBOOST_PARAM_STRENGTH_SUPPORTED,
+ BASSBOOST_PARAM_STRENGTH
+} t_bassboost_params;
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECTBASSBOOSTAPI_H_*/
diff --git a/include/media/EffectReverbApi.h b/include/media/EffectEnvironmentalReverbApi.h
index 6371adb..d490f71 100644
--- a/include/media/EffectReverbApi.h
+++ b/include/media/EffectEnvironmentalReverbApi.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_EFFECTREVERBAPI_H_
-#define ANDROID_EFFECTREVERBAPI_H_
+#ifndef ANDROID_EFFECTENVIRONMENTALREVERBAPI_H_
+#define ANDROID_EFFECTENVIRONMENTALREVERBAPI_H_
#include <media/EffectApi.h>
@@ -27,14 +27,9 @@ extern "C" {
static const effect_uuid_t SL_IID_ENVIRONMENTALREVERB_ = { 0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, { 0x4e, 0x23, 0x4d, 0x6, 0x83, 0x9e } };
const effect_uuid_t * const SL_IID_ENVIRONMENTALREVERB = &SL_IID_ENVIRONMENTALREVERB_;
-static const effect_uuid_t SL_IID_PRESETREVERB_ = { 0x47382d60, 0xddd8, 0x11db, 0xbf3a, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
-const effect_uuid_t * const SL_IID_PRESETREVERB = &SL_IID_PRESETREVERB_;
-
-/* enumerated parameter settings for Reverb effect */
+/* enumerated parameter settings for environmental reverb effect */
typedef enum
{
- REVERB_PARAM_BYPASS,
- REVERB_PARAM_PRESET,
// Parameters below are as defined in OpenSL ES specification for environmental reverb interface
REVERB_PARAM_ROOM_LEVEL, // in millibels, range -6000 to 0
REVERB_PARAM_ROOM_HF_LEVEL, // in millibels, range -4000 to 0
@@ -46,17 +41,9 @@ typedef enum
REVERB_PARAM_REVERB_DELAY, // in milliseconds, range 0 to 65
REVERB_PARAM_DIFFUSION, // in permilles, range 0 to 1000
REVERB_PARAM_DENSITY, // in permilles, range 0 to 1000
- REVERB_PARAM_PROPERTIES
-} t_reverb_params;
-
-
-typedef enum
-{
- REVERB_PRESET_LARGE_HALL,
- REVERB_PRESET_HALL,
- REVERB_PRESET_CHAMBER,
- REVERB_PRESET_ROOM,
-} t_reverb_presets;
+ REVERB_PARAM_PROPERTIES,
+ REVERB_PARAM_BYPASS
+} t_env_reverb_params;
//t_reverb_properties is equal to SLEnvironmentalReverbSettings defined in OpenSL ES specification.
typedef struct s_reverb_properties {
@@ -79,4 +66,4 @@ typedef struct s_reverb_properties {
#endif
-#endif /*ANDROID_EFFECTREVERBAPI_H_*/
+#endif /*ANDROID_EFFECTENVIRONMENTALREVERBAPI_H_*/
diff --git a/include/media/EffectPresetReverbApi.h b/include/media/EffectPresetReverbApi.h
new file mode 100644
index 0000000..34ffffe
--- /dev/null
+++ b/include/media/EffectPresetReverbApi.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_EFFECTPRESETREVERBAPI_H_
+#define ANDROID_EFFECTPRESETREVERBAPI_H_
+
+#include <media/EffectApi.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// TODO: include OpenSLES_IID.h instead
+
+static const effect_uuid_t SL_IID_PRESETREVERB_ = { 0x47382d60, 0xddd8, 0x11db, 0xbf3a, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+const effect_uuid_t * const SL_IID_PRESETREVERB = &SL_IID_PRESETREVERB_;
+
+/* enumerated parameter settings for preset reverb effect */
+typedef enum
+{
+ REVERB_PARAM_PRESET
+} t_preset_reverb_params;
+
+
+typedef enum
+{
+ REVERB_PRESET_NONE,
+ REVERB_PRESET_SMALLROOM,
+ REVERB_PRESET_MEDIUMROOM,
+ REVERB_PRESET_LARGEROOM,
+ REVERB_PRESET_MEDIUMHALL,
+ REVERB_PRESET_LARGEHALL,
+ REVERB_PRESET_PLATE
+} t_reverb_presets;
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECTPRESETREVERBAPI_H_*/
diff --git a/include/media/EffectVirtualizerApi.h b/include/media/EffectVirtualizerApi.h
new file mode 100644
index 0000000..601c384
--- /dev/null
+++ b/include/media/EffectVirtualizerApi.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_EFFECTVIRTUALIZERAPI_H_
+#define ANDROID_EFFECTVIRTUALIZERAPI_H_
+
+#include <media/EffectApi.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// TODO: include OpenSLES_IID.h instead
+static const effect_uuid_t SL_IID_VIRTUALIZER_ = { 0x37cc2c00, 0xdddd, 0x11db, 0x8577, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+const effect_uuid_t * const SL_IID_VIRTUALIZER = &SL_IID_VIRTUALIZER_;
+
+/* enumerated parameter settings for virtualizer effect */
+typedef enum
+{
+ VIRTUALIZER_PARAM_STRENGTH_SUPPORTED,
+ VIRTUALIZER_PARAM_STRENGTH
+} t_virtualizer_params;
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECTVIRTUALIZERAPI_H_*/
diff --git a/include/media/MediaRecorderBase.h b/include/media/MediaRecorderBase.h
index 497965c..5e9e368 100644
--- a/include/media/MediaRecorderBase.h
+++ b/include/media/MediaRecorderBase.h
@@ -48,6 +48,7 @@ struct MediaRecorderBase {
virtual status_t close() = 0;
virtual status_t reset() = 0;
virtual status_t getMaxAmplitude(int *max) = 0;
+ virtual status_t dump(int fd, const Vector<String16>& args) const = 0;
private:
MediaRecorderBase(const MediaRecorderBase &);
diff --git a/include/media/PVMediaRecorder.h b/include/media/PVMediaRecorder.h
index c04105e..f75d80d 100644
--- a/include/media/PVMediaRecorder.h
+++ b/include/media/PVMediaRecorder.h
@@ -52,6 +52,7 @@ public:
virtual status_t close();
virtual status_t reset();
virtual status_t getMaxAmplitude(int *max);
+ virtual status_t dump(int fd, const Vector<String16>& args) const;
private:
status_t doStop();
diff --git a/include/ui/Rect.h b/include/ui/Rect.h
index a213c09..4e65a2d 100644
--- a/include/ui/Rect.h
+++ b/include/ui/Rect.h
@@ -20,31 +20,28 @@
#include <utils/TypeHelpers.h>
#include <ui/Point.h>
+#include <android/rect.h>
+
namespace android {
-class Rect
+class Rect : public ARect
{
public:
- int left;
- int top;
- int right;
- int bottom;
-
- typedef int value_type;
+ typedef int32_t value_type;
// we don't provide copy-ctor and operator= on purpose
// because we want the compiler generated versions
inline Rect() {
}
- inline Rect(int w, int h)
- : left(0), top(0), right(w), bottom(h) {
+ inline Rect(int32_t w, int32_t h) {
+ left = top = 0; right = w; bottom = h;
}
- inline Rect(int l, int t, int r, int b)
- : left(l), top(t), right(r), bottom(b) {
+ inline Rect(int32_t l, int32_t t, int32_t r, int32_t b) {
+ left = l; top = t; right = r; bottom = b;
}
- inline Rect(const Point& lt, const Point& rb)
- : left(lt.x), top(lt.y), right(rb.x), bottom(rb.y) {
+ inline Rect(const Point& lt, const Point& rb) {
+ left = lt.x; top = lt.y; right = rb.x; bottom = rb.y;
}
void makeInvalid();
@@ -68,12 +65,12 @@ public:
}
// rectangle's width
- inline int width() const {
+ inline int32_t width() const {
return right-left;
}
// rectangle's height
- inline int height() const {
+ inline int32_t height() const {
return bottom-top;
}
@@ -136,12 +133,12 @@ public:
const Rect operator + (const Point& rhs) const;
const Rect operator - (const Point& rhs) const;
- void translate(int dx, int dy) { // legacy, don't use.
+ void translate(int32_t dx, int32_t dy) { // legacy, don't use.
offsetBy(dx, dy);
}
- Rect& offsetTo(int x, int y);
- Rect& offsetBy(int x, int y);
+ Rect& offsetTo(int32_t x, int32_t y);
+ Rect& offsetBy(int32_t x, int32_t y);
bool intersect(const Rect& with, Rect* result) const;
};
diff --git a/include/utils/PollLoop.h b/include/utils/PollLoop.h
index b3651ca..81230e8 100644
--- a/include/utils/PollLoop.h
+++ b/include/utils/PollLoop.h
@@ -42,7 +42,7 @@ protected:
virtual ~PollLoop();
public:
- PollLoop();
+ PollLoop(bool allowNonCallbacks);
/**
* A callback that it to be invoked when an event occurs on a file descriptor.
@@ -54,6 +54,12 @@ public:
*/
typedef bool (*Callback)(int fd, int events, void* data);
+ enum {
+ POLL_CALLBACK = ALOOPER_POLL_CALLBACK,
+ POLL_TIMEOUT = ALOOPER_POLL_TIMEOUT,
+ POLL_ERROR = ALOOPER_POLL_ERROR,
+ };
+
/**
* Performs a single call to poll() with optional timeout in milliseconds.
* Invokes callbacks for all file descriptors on which an event occurred.
@@ -61,16 +67,25 @@ public:
* If the timeout is zero, returns immediately without blocking.
* If the timeout is negative, waits indefinitely until awoken.
*
- * Returns true if a callback was invoked or if the loop was awoken by wake().
- * Returns false if a timeout or error occurred.
+ * Returns ALOOPER_POLL_CALLBACK if a callback was invoked.
+ *
+ * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
+ * timeout expired.
+ *
+ * Returns ALOPER_POLL_ERROR if an error occurred.
*
- * This method must only be called on the main thread.
+ * Returns a value >= 0 containing a file descriptor if it has data
+ * and it has no callback function (requiring the caller here to handle it).
+ * In this (and only this) case outEvents and outData will contain the poll
+ * events and data associated with the fd.
+ *
+ * This method must only be called on the thread owning the PollLoop.
* This method blocks until either a file descriptor is signalled, a timeout occurs,
* or wake() is called.
* This method does not return until it has finished invoking the appropriate callbacks
* for all file descriptors that were signalled.
*/
- bool pollOnce(int timeoutMillis);
+ int32_t pollOnce(int timeoutMillis, int* outEvents = NULL, void** outData = NULL);
/**
* Wakes the loop asynchronously.
@@ -81,6 +96,12 @@ public:
void wake();
/**
+ * Control whether this PollLoop instance allows using IDs instead
+ * of callbacks.
+ */
+ bool getAllowNonCallbacks() const;
+
+ /**
* Sets the callback for a file descriptor, replacing the existing one, if any.
* It is an error to call this method with events == 0 or callback == NULL.
*
@@ -95,7 +116,8 @@ public:
/**
* Like setCallback(), but for the NDK callback function.
*/
- void setLooperCallback(int fd, int events, ALooper_callbackFunc* callback, void* data);
+ void setLooperCallback(int fd, int events, ALooper_callbackFunc* callback,
+ void* data);
/**
* Removes the callback for a file descriptor, if one exists.
@@ -141,7 +163,9 @@ private:
ALooper_callbackFunc* looperCallback;
void* data;
};
-
+
+ const bool mAllowNonCallbacks;
+
Mutex mLock;
bool mPolling;
uint32_t mWaiters;
@@ -155,7 +179,9 @@ private:
Vector<RequestedCallback> mRequestedCallbacks;
Vector<PendingCallback> mPendingCallbacks; // used privately by pollOnce
-
+ Vector<PendingCallback> mPendingFds; // used privately by pollOnce
+ size_t mPendingFdsPos;
+
void openWakePipe();
void closeWakePipe();
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index 42a7fc6..f809cba 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -54,7 +54,7 @@ static inline nsecs_t now() {
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
mPolicy(policy) {
- mPollLoop = new PollLoop();
+ mPollLoop = new PollLoop(false);
mInboundQueue.head.refCount = -1;
mInboundQueue.head.type = EventEntry::TYPE_SENTINEL;
diff --git a/libs/ui/Rect.cpp b/libs/ui/Rect.cpp
index 66b9576..5694e00 100644
--- a/libs/ui/Rect.cpp
+++ b/libs/ui/Rect.cpp
@@ -18,11 +18,11 @@
namespace android {
-static inline int min(int a, int b) {
+static inline int32_t min(int32_t a, int32_t b) {
return (a<b) ? a : b;
}
-static inline int max(int a, int b) {
+static inline int32_t max(int32_t a, int32_t b) {
return (a>b) ? a : b;
}
@@ -53,7 +53,7 @@ bool Rect::operator < (const Rect& rhs) const
return false;
}
-Rect& Rect::offsetTo(int x, int y)
+Rect& Rect::offsetTo(int32_t x, int32_t y)
{
right -= left - x;
bottom -= top - y;
@@ -62,7 +62,7 @@ Rect& Rect::offsetTo(int x, int y)
return *this;
}
-Rect& Rect::offsetBy(int x, int y)
+Rect& Rect::offsetBy(int32_t x, int32_t y)
{
left += x;
top += y;
diff --git a/libs/utils/PollLoop.cpp b/libs/utils/PollLoop.cpp
index 58fe141..f740fa0 100644
--- a/libs/utils/PollLoop.cpp
+++ b/libs/utils/PollLoop.cpp
@@ -25,8 +25,9 @@ static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
static bool gHaveTLS = false;
static pthread_key_t gTLS = 0;
-PollLoop::PollLoop() :
- mPolling(false), mWaiters(0) {
+PollLoop::PollLoop(bool allowNonCallbacks) :
+ mAllowNonCallbacks(allowNonCallbacks), mPolling(false),
+ mWaiters(0), mPendingFdsPos(0) {
openWakePipe();
}
@@ -106,7 +107,18 @@ void PollLoop::closeWakePipe() {
// method is currently only called by the destructor.
}
-bool PollLoop::pollOnce(int timeoutMillis) {
+int32_t PollLoop::pollOnce(int timeoutMillis, int* outEvents, void** outData) {
+ // If there are still pending fds from the last call, dispatch those
+ // first, to avoid an earlier fd from starving later ones.
+ const size_t pendingFdsCount = mPendingFds.size();
+ if (mPendingFdsPos < pendingFdsCount) {
+ const PendingCallback& pending = mPendingFds.itemAt(mPendingFdsPos);
+ mPendingFdsPos++;
+ if (outEvents != NULL) *outEvents = pending.events;
+ if (outData != NULL) *outData = pending.data;
+ return pending.fd;
+ }
+
mLock.lock();
while (mWaiters != 0) {
mResume.wait(mLock);
@@ -114,7 +126,7 @@ bool PollLoop::pollOnce(int timeoutMillis) {
mPolling = true;
mLock.unlock();
- bool result;
+ int32_t result;
size_t requestedCount = mRequestedFds.size();
#if DEBUG_POLL_AND_WAKE
@@ -131,7 +143,7 @@ bool PollLoop::pollOnce(int timeoutMillis) {
#if DEBUG_POLL_AND_WAKE
LOGD("%p ~ pollOnce - timeout", this);
#endif
- result = false;
+ result = POLL_TIMEOUT;
goto Done;
}
@@ -143,7 +155,7 @@ bool PollLoop::pollOnce(int timeoutMillis) {
if (errno != EINTR) {
LOGW("Poll failed with an unexpected error, errno=%d", errno);
}
- result = false;
+ result = POLL_ERROR;
goto Done;
}
@@ -156,38 +168,44 @@ bool PollLoop::pollOnce(int timeoutMillis) {
#endif
mPendingCallbacks.clear();
+ mPendingFds.clear();
+ mPendingFdsPos = 0;
+ if (outEvents != NULL) *outEvents = 0;
+ if (outData != NULL) *outData = NULL;
+
+ result = POLL_CALLBACK;
for (size_t i = 0; i < requestedCount; i++) {
const struct pollfd& requestedFd = mRequestedFds.itemAt(i);
short revents = requestedFd.revents;
if (revents) {
const RequestedCallback& requestedCallback = mRequestedCallbacks.itemAt(i);
- Callback callback = requestedCallback.callback;
- ALooper_callbackFunc* looperCallback = requestedCallback.looperCallback;
-
- if (callback || looperCallback) {
- PendingCallback pendingCallback;
- pendingCallback.fd = requestedFd.fd;
- pendingCallback.events = requestedFd.revents;
- pendingCallback.callback = callback;
- pendingCallback.looperCallback = looperCallback;
- pendingCallback.data = requestedCallback.data;
- mPendingCallbacks.push(pendingCallback);
+ PendingCallback pending;
+ pending.fd = requestedFd.fd;
+ pending.events = revents;
+ pending.callback = requestedCallback.callback;
+ pending.looperCallback = requestedCallback.looperCallback;
+ pending.data = requestedCallback.data;
+
+ if (pending.callback || pending.looperCallback) {
+ mPendingCallbacks.push(pending);
+ } else if (pending.fd != mWakeReadPipeFd) {
+ if (result == POLL_CALLBACK) {
+ result = pending.fd;
+ if (outEvents != NULL) *outEvents = pending.events;
+ if (outData != NULL) *outData = pending.data;
+ } else {
+ mPendingFds.push(pending);
+ }
} else {
- if (requestedFd.fd == mWakeReadPipeFd) {
#if DEBUG_POLL_AND_WAKE
- LOGD("%p ~ pollOnce - awoken", this);
-#endif
- char buffer[16];
- ssize_t nRead;
- do {
- nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
- } while (nRead == sizeof(buffer));
- } else {
-#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
- LOGD("%p ~ pollOnce - fd %d has no callback!", this, requestedFd.fd);
+ LOGD("%p ~ pollOnce - awoken", this);
#endif
- }
+ char buffer[16];
+ ssize_t nRead;
+ do {
+ nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
+ } while (nRead == sizeof(buffer));
}
respondedCount -= 1;
@@ -196,7 +214,6 @@ bool PollLoop::pollOnce(int timeoutMillis) {
}
}
}
- result = true;
Done:
mLock.lock();
@@ -206,7 +223,7 @@ Done:
}
mLock.unlock();
- if (result) {
+ if (result == POLL_CALLBACK || result >= 0) {
size_t pendingCount = mPendingCallbacks.size();
for (size_t i = 0; i < pendingCount; i++) {
const PendingCallback& pendingCallback = mPendingCallbacks.itemAt(i);
@@ -247,6 +264,10 @@ void PollLoop::wake() {
}
}
+bool PollLoop::getAllowNonCallbacks() const {
+ return mAllowNonCallbacks;
+}
+
void PollLoop::setCallback(int fd, int events, Callback callback, void* data) {
setCallbackCommon(fd, events, callback, NULL, data);
}
@@ -263,12 +284,18 @@ void PollLoop::setCallbackCommon(int fd, int events, Callback callback,
LOGD("%p ~ setCallback - fd=%d, events=%d", this, fd, events);
#endif
- if (! events || (! callback && ! looperCallback)) {
- LOGE("Invalid attempt to set a callback with no selected poll events or no callback.");
+ if (! events) {
+ LOGE("Invalid attempt to set a callback with no selected poll events.");
removeCallback(fd);
return;
}
+ if (! callback && ! looperCallback && ! mAllowNonCallbacks) {
+ LOGE("Invalid attempt to set NULL callback but not allowed.");
+ removeCallback(fd);
+ return;
+ }
+
wakeAndLock();
struct pollfd requestedFd;
diff --git a/libs/utils/tests/PollLoop_test.cpp b/libs/utils/tests/PollLoop_test.cpp
index 4848c0f..02f1808 100644
--- a/libs/utils/tests/PollLoop_test.cpp
+++ b/libs/utils/tests/PollLoop_test.cpp
@@ -87,7 +87,7 @@ protected:
sp<PollLoop> mPollLoop;
virtual void SetUp() {
- mPollLoop = new PollLoop();
+ mPollLoop = new PollLoop(false);
}
virtual void TearDown() {
@@ -98,26 +98,26 @@ protected:
TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndNotAwoken_WaitsForTimeoutAndReturnsFalse) {
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(100);
+ int32_t result = mPollLoop->pollOnce(100);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should approx. equal timeout";
- EXPECT_FALSE(result)
- << "pollOnce result should be false because timeout occurred";
+ EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+ << "pollOnce result should be POLL_TIMEOUT";
}
TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndAwokenBeforeWaiting_ImmediatelyReturnsTrue) {
mPollLoop->wake();
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(1000);
+ int32_t result = mPollLoop->pollOnce(1000);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should approx. zero because wake() was called before waiting";
- EXPECT_TRUE(result)
- << "pollOnce result should be true because loop was awoken";
+ EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+ << "pollOnce result should be POLL_CALLBACK because loop was awoken";
}
TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndAwokenWhileWaiting_PromptlyReturnsTrue) {
@@ -125,24 +125,24 @@ TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndAwokenWhileWaiting_PromptlyRe
delayedWake->run();
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(1000);
+ int32_t result = mPollLoop->pollOnce(1000);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should approx. equal wake delay";
- EXPECT_TRUE(result)
- << "pollOnce result should be true because loop was awoken";
+ EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+ << "pollOnce result should be POLL_CALLBACK because loop was awoken";
}
TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndNoRegisteredFDs_ImmediatelyReturnsFalse) {
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(0);
+ int32_t result = mPollLoop->pollOnce(0);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should be approx. zero";
- EXPECT_FALSE(result)
- << "pollOnce result should be false because timeout occurred";
+ EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+ << "pollOnce result should be POLL_TIMEOUT";
}
TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndNoSignalledFDs_ImmediatelyReturnsFalse) {
@@ -152,13 +152,13 @@ TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndNoSignalledFDs_ImmediatelyReturn
handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(0);
+ int32_t result = mPollLoop->pollOnce(0);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should be approx. zero";
- EXPECT_FALSE(result)
- << "pollOnce result should be false because timeout occurred";
+ EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+ << "pollOnce result should be POLL_TIMEOUT";
EXPECT_EQ(0, handler.callbackCount)
<< "callback should not have been invoked because FD was not signalled";
}
@@ -171,13 +171,13 @@ TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndSignalledFD_ImmediatelyInvokesCa
handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(0);
+ int32_t result = mPollLoop->pollOnce(0);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should be approx. zero";
- EXPECT_TRUE(result)
- << "pollOnce result should be true because FD was signalled";
+ EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+ << "pollOnce result should be POLL_CALLBACK because FD was signalled";
EXPECT_EQ(1, handler.callbackCount)
<< "callback should be invoked exactly once";
EXPECT_EQ(pipe.receiveFd, handler.fd)
@@ -193,13 +193,13 @@ TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndNoSignalledFDs_WaitsForTimeou
handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(100);
+ int32_t result = mPollLoop->pollOnce(100);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should approx. equal timeout";
- EXPECT_FALSE(result)
- << "pollOnce result should be false because timeout occurred";
+ EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+ << "pollOnce result should be POLL_TIMEOUT";
EXPECT_EQ(0, handler.callbackCount)
<< "callback should not have been invoked because FD was not signalled";
}
@@ -212,15 +212,15 @@ TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDBeforeWaiting_Imme
handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(100);
+ int32_t result = mPollLoop->pollOnce(100);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
ASSERT_EQ(OK, pipe.readSignal())
<< "signal should actually have been written";
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should be approx. zero";
- EXPECT_TRUE(result)
- << "pollOnce result should be true because FD was signalled";
+ EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+ << "pollOnce result should be POLL_CALLBACK because FD was signalled";
EXPECT_EQ(1, handler.callbackCount)
<< "callback should be invoked exactly once";
EXPECT_EQ(pipe.receiveFd, handler.fd)
@@ -238,15 +238,15 @@ TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDWhileWaiting_Promp
delayedWriteSignal->run();
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(1000);
+ int32_t result = mPollLoop->pollOnce(1000);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
ASSERT_EQ(OK, pipe.readSignal())
<< "signal should actually have been written";
EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should approx. equal signal delay";
- EXPECT_TRUE(result)
- << "pollOnce result should be true because FD was signalled";
+ EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+ << "pollOnce result should be POLL_CALLBACK because FD was signalled";
EXPECT_EQ(1, handler.callbackCount)
<< "callback should be invoked exactly once";
EXPECT_EQ(pipe.receiveFd, handler.fd)
@@ -264,15 +264,15 @@ TEST_F(PollLoopTest, PollOnce_WhenCallbackAddedThenRemoved_CallbackShouldNotBeIn
mPollLoop->removeCallback(pipe.receiveFd);
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(100);
+ int32_t result = mPollLoop->pollOnce(100);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
ASSERT_EQ(OK, pipe.readSignal())
<< "signal should actually have been written";
EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should approx. equal timeout because FD was no longer registered";
- EXPECT_FALSE(result)
- << "pollOnce result should be false because timeout occurred";
+ EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+ << "pollOnce result should be POLL_TIMEOUT";
EXPECT_EQ(0, handler.callbackCount)
<< "callback should not be invoked";
}
@@ -287,15 +287,15 @@ TEST_F(PollLoopTest, PollOnce_WhenCallbackReturnsFalse_CallbackShouldNotBeInvoke
pipe.writeSignal();
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(0);
+ int32_t result = mPollLoop->pollOnce(0);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
ASSERT_EQ(OK, pipe.readSignal())
<< "signal should actually have been written";
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should approx. equal zero because FD was already signalled";
- EXPECT_TRUE(result)
- << "pollOnce result should be true because FD was signalled";
+ EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+ << "pollOnce result should be POLL_CALLBACK because FD was signalled";
EXPECT_EQ(1, handler.callbackCount)
<< "callback should be invoked";
@@ -310,8 +310,8 @@ TEST_F(PollLoopTest, PollOnce_WhenCallbackReturnsFalse_CallbackShouldNotBeInvoke
<< "signal should actually have been written";
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should approx. equal zero because timeout was zero";
- EXPECT_FALSE(result)
- << "pollOnce result should be false because timeout occurred";
+ EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+ << "pollOnce result should be POLL_TIMEOUT";
EXPECT_EQ(1, handler.callbackCount)
<< "callback should not be invoked this time";
}
@@ -351,15 +351,15 @@ TEST_F(PollLoopTest, PollOnce_WhenCallbackAddedTwice_OnlySecondCallbackShouldBeI
pipe.writeSignal(); // would cause FD to be considered signalled
StopWatch stopWatch("pollOnce");
- bool result = mPollLoop->pollOnce(100);
+ int32_t result = mPollLoop->pollOnce(100);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
ASSERT_EQ(OK, pipe.readSignal())
<< "signal should actually have been written";
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should approx. zero because FD was already signalled";
- EXPECT_TRUE(result)
- << "pollOnce result should be true because FD was signalled";
+ EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+ << "pollOnce result should be POLL_CALLBACK because FD was signalled";
EXPECT_EQ(0, handler1.callbackCount)
<< "original handler callback should not be invoked because it was replaced";
EXPECT_EQ(1, handler2.callbackCount)
diff --git a/media/java/android/media/BassBoost.java b/media/java/android/media/BassBoost.java
new file mode 100644
index 0000000..ef4ce05
--- /dev/null
+++ b/media/java/android/media/BassBoost.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2009 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 android.media;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+
+import android.media.AudioEffect;
+
+/**
+ * Bass boost is an audio effect to boost or amplify low frequencies of the sound. It is comparable
+ * to an simple equalizer but limited to one band amplification in the low frequency range.
+ * <p>An application creates a BassBoost object to instantiate and control a bass boost engine
+ * in the audio framework.
+ * <p>The methods, parameter types and units exposed by the BassBoost implementation are directly
+ * mapping those defined by the OpenSL ES 1.0.1 Specification (http://www.khronos.org/opensles/)
+ * for the SLBassBoostItf interface. Please refer to this specification for more details.
+ * <p>To attach the BassBoost to a particular AudioTrack or MediaPlayer, specify the audio session
+ * ID of this AudioTrack or MediaPlayer when constructing the BassBoost. If the audio session ID 0
+ * is specified, the BassBoost applies to the main audio output mix.
+ // TODO when AudioEffect is unhidden
+ // <p> See {_at_link android.media.AudioEffect} class for more details on controlling audio effects.
+ *
+ * {@hide Pending API council review}
+ */
+
+public class BassBoost extends AudioEffect {
+
+ private final static String TAG = "BassBoost";
+
+ // These constants must be synchronized with those in
+ // frameworks/base/include/media/EffectBassBoostApi.h
+ /**
+ * Is strength parameter supported by bass boost engine. Parameter ID for getParameter().
+ */
+ public static final int PARAM_STRENGTH_SUPPORTED = 0;
+ /**
+ * Bass boost effect strength. Parameter ID for
+ * {@link android.media.BassBoost.OnParameterChangeListener}
+ */
+ public static final int PARAM_STRENGTH = 1;
+
+ /**
+ * Indicates if strength parameter is supported by the bass boost engine
+ */
+ private boolean mStrengthSupported = false;
+
+ /**
+ * Registered listener for parameter changes.
+ */
+ private OnParameterChangeListener mParamListener = null;
+
+ /**
+ * Listener used internally to to receive raw parameter change event from AudioEffect super class
+ */
+ private BaseParameterListener mBaseParamListener = null;
+
+ /**
+ * Lock for access to mParamListener
+ */
+ private final Object mParamListenerLock = new Object();
+
+ /**
+ * Class constructor.
+ * @param priority the priority level requested by the application for controlling the BassBoost
+ * engine. As the same engine can be shared by several applications, this parameter indicates
+ * how much the requesting application needs control of effect parameters. The normal priority
+ * is 0, above normal is a positive number, below normal a negative number.
+ * @param audioSession System wide unique audio session identifier. If audioSession
+ * is not 0, the BassBoost will be attached to the MediaPlayer or AudioTrack in the
+ * same audio session. Otherwise, the BassBoost will apply to the output mix.
+ *
+ * @throws java.lang.IllegalStateException
+ * @throws java.lang.IllegalArgumentException
+ * @throws java.lang.UnsupportedOperationException
+ * @throws java.lang.RuntimeException
+ */
+ public BassBoost(int priority, int audioSession)
+ throws IllegalStateException, IllegalArgumentException,
+ UnsupportedOperationException, RuntimeException {
+ super(EFFECT_TYPE_BASS_BOOST, EFFECT_TYPE_NULL, priority, audioSession);
+
+ short[] value = new short[1];
+ checkStatus(getParameter(PARAM_STRENGTH_SUPPORTED, value));
+ mStrengthSupported = (value[0] != 0);
+ }
+
+ /**
+ * Indicates whether setting strength is supported. If this method returns false, only one
+ * strength is supported and the setStrength() method always rounds to that value.
+ * @return true is strength parameter is supported, false otherwise
+ */
+ public boolean getStrengthSupported() {
+ return mStrengthSupported;
+ }
+
+ /**
+ * Sets the strength of the bass boost effect. If the implementation does not support per mille
+ * accuracy for setting the strength, it is allowed to round the given strength to the nearest
+ * supported value. You can use the {@link #getRoundedStrength()} method to query the
+ * (possibly rounded) value that was actually set.
+ * @param strength Strength of the effect. The valid range for strength strength is [0, 1000],
+ * where 0 per mille designates the mildest effect and 1000 per mille designates the strongest.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public void setStrength(short strength)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ checkStatus(setParameter(PARAM_STRENGTH, strength));
+ }
+
+ /**
+ * Gets the current strength of the effect.
+ * @return The strength of the effect. The valid range for strength is [0, 1000], where 0 per
+ * mille designates the mildest effect and 1000 per mille the strongest
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public short getRoundedStrength()
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ short[] value = new short[1];
+ checkStatus(getParameter(PARAM_STRENGTH, value));
+ return value[0];
+ }
+
+ /**
+ * The OnParameterChangeListener interface defines a method called by the BassBoost when a
+ * parameter value has changed.
+ */
+ public interface OnParameterChangeListener {
+ /**
+ * Method called when a parameter value has changed. The method is called only if the
+ * parameter was changed by another application having the control of the same
+ * BassBoost engine.
+ * @param effect the BassBoost on which the interface is registered.
+ * @param status status of the set parameter operation.
+ // TODO when AudioEffect is unhidden
+ // See {_at_link android.media.AudioEffect#setParameter(byte[], byte[])}.
+ * @param param ID of the modified parameter. See {@link #PARAM_STRENGTH} ...
+ * @param value the new parameter value.
+ */
+ void onParameterChange(BassBoost effect, int status, int param, short value);
+ }
+
+ /**
+ * Listener used internally to receive unformatted parameter change events from AudioEffect
+ * super class.
+ */
+ private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+ private BaseParameterListener() {
+
+ }
+ public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+ OnParameterChangeListener l = null;
+
+ synchronized (mParamListenerLock) {
+ if (mParamListener != null) {
+ l = mParamListener;
+ }
+ }
+ if (l != null) {
+ int p = -1;
+ short v = -1;
+
+ if (param.length == 4) {
+ p = byteArrayToInt(param, 0);
+ }
+ if (value.length == 2) {
+ v = byteArrayToShort(value, 0);
+ }
+ if (p != -1 && v != -1) {
+ l.onParameterChange(BassBoost.this, status, p, v);
+ }
+ }
+ }
+ }
+
+ /**
+ * Registers an OnParameterChangeListener interface.
+ * @param listener OnParameterChangeListener interface registered
+ */
+ public void setParameterListener(OnParameterChangeListener listener) {
+ synchronized (mParamListenerLock) {
+ if (mParamListener == null) {
+ mParamListener = listener;
+ mBaseParamListener = new BaseParameterListener();
+ super.setParameterListener(mBaseParamListener);
+ }
+ }
+ }
+}
diff --git a/media/java/android/media/EnvironmentalReverb.java b/media/java/android/media/EnvironmentalReverb.java
new file mode 100644
index 0000000..88230fc
--- /dev/null
+++ b/media/java/android/media/EnvironmentalReverb.java
@@ -0,0 +1,504 @@
+/*
+ * Copyright (C) 2009 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 android.media;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+
+import android.media.AudioEffect;
+
+/**
+ * A sound generated within a room travels in many directions. The listener first hears the
+ * direct sound from the source itself. Later, he or she hears discrete echoes caused by sound
+ * bouncing off nearby walls, the ceiling and the floor. As sound waves arrive after
+ * undergoing more and more reflections, individual reflections become indistinguishable and
+ * the listener hears continuous reverberation that decays over time.
+ * Reverb is vital for modeling a listener's environment. It can be used in music applications
+ * to simulate music being played back in various environments, or in games to immerse the
+ * listener within the game's environment.
+ * The EnvironmentalReverb class allows an application to control each reverb engine property in a
+ * global reverb environment and is more suitable for games. For basic control, more suitable for
+ * music applications, it is recommended to use the
+ // TODO when PresetReverb is unhidden
+ // {_at_link android.media.PresetReverb} class.
+ * <p>An application creates a EnvironmentalReverb object to instantiate and control a reverb engine
+ * in the audio framework.
+ * <p>The methods, parameter types and units exposed by the EnvironmentalReverb implementation are
+ * directly mapping those defined by the OpenSL ES 1.0.1 Specification
+ * (http://www.khronos.org/opensles/) for the SLEnvironmentalReverbItf interface.
+ * Please refer to this specification for more details.
+ * <p>The EnvironmentalReverb is an output mix auxiliary effect and should be created on
+ * Audio session 0. In order for a MediaPlayer or AudioTrack to be fed into this effect,
+ * they must be explicitely attached to it and a send level must be specified. Use the effect ID
+ * returned by getId() method to designate this particular effect when attaching it to the
+ * MediaPlayer or AudioTrack.
+ // TODO when AudioEffect is unhidden
+ // <p> See {_at_link android.media.AudioEffect} class for more details on controlling
+ * audio effects.
+ *
+ * {@hide Pending API council review}
+ */
+
+public class EnvironmentalReverb extends AudioEffect {
+
+ private final static String TAG = "EnvironmentalReverb";
+
+ // These constants must be synchronized with those in
+ // frameworks/base/include/media/EffectEnvironmentalReverbApi.h
+
+ /**
+ * Room level. Parameter ID for
+ * {@link android.media.EnvironmentalReverb.OnParameterChangeListener}
+ */
+ public static final int PARAM_ROOM_LEVEL = 0;
+ /**
+ * Room HF level. Parameter ID for OnParameterChangeListener
+ */
+ public static final int PARAM_ROOM_HF_LEVEL = 1;
+ /**
+ * Decay time. Parameter ID for OnParameterChangeListener
+ */
+ public static final int PARAM_DECAY_TIME = 2;
+ /**
+ * Decay HF ratio. Parameter ID for OnParameterChangeListener
+ */
+ public static final int PARAM_DECAY_HF_RATIO = 3;
+ /**
+ * Early reflections level. Parameter ID for OnParameterChangeListener
+ */
+ public static final int PARAM_REFLECTIONS_LEVEL = 4;
+ /**
+ * Early reflections delay. Parameter ID for OnParameterChangeListener
+ */
+ public static final int PARAM_REFLECTIONS_DELAY = 5;
+ /**
+ * Reverb level. Parameter ID for OnParameterChangeListener
+ */
+ public static final int PARAM_REVERB_LEVEL = 6;
+ /**
+ * Reverb delay. Parameter ID for OnParameterChangeListener
+ */
+ public static final int PARAM_REVERB_DELAY = 7;
+ /**
+ * Diffusion. Parameter ID for OnParameterChangeListener
+ */
+ public static final int PARAM_DIFFUSION = 8;
+ /**
+ * Density. Parameter ID for OnParameterChangeListener
+ */
+ public static final int PARAM_DENSITY = 9;
+
+ /**
+ * Registered listener for parameter changes
+ */
+ private OnParameterChangeListener mParamListener = null;
+
+ /**
+ * Listener used internally to to receive raw parameter change event from AudioEffect super
+ * class
+ */
+ private BaseParameterListener mBaseParamListener = null;
+
+ /**
+ * Lock for access to mParamListener
+ */
+ private final Object mParamListenerLock = new Object();
+
+ /**
+ * Class constructor.
+ * @param priority the priority level requested by the application for controlling the
+ * EnvironmentalReverb engine. As the same engine can be shared by several applications, this
+ * parameter indicates how much the requesting application needs control of effect parameters.
+ * The normal priority is 0, above normal is a positive number, below normal a negative number.
+ * @param audioSession System wide unique audio session identifier. If audioSession
+ * is not 0, the EnvironmentalReverb will be attached to the MediaPlayer or AudioTrack in the
+ * same audio session. Otherwise, the EnvironmentalReverb will apply to the output mix.
+ * As the EnvironmentalReverb is an auxiliary effect it is recommended to instantiate it on
+ * audio session 0 and to attach it to the MediaPLayer auxiliary output.
+ *
+ * @throws java.lang.IllegalArgumentException
+ * @throws java.lang.UnsupportedOperationException
+ * @throws java.lang.RuntimeException
+ */
+ public EnvironmentalReverb(int priority, int audioSession)
+ throws IllegalArgumentException, UnsupportedOperationException, RuntimeException {
+ super(EFFECT_TYPE_ENV_REVERB, EFFECT_TYPE_NULL, priority, audioSession);
+ Log.e(TAG, "contructor");
+ }
+
+ /**
+ * Sets the master volume level of the environmental reverb effect.
+ * @param room Room level in millibels. The valid range is [-9000, 0].
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public void setRoomLevel(short room)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ byte[] param = shortToByteArray(room);
+ checkStatus(setParameter(PARAM_ROOM_LEVEL, param));
+ }
+
+ /**
+ * Gets the master volume level of the environmental reverb effect.
+ * @return the room level in millibels.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public short getRoomLevel()
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ byte[] param = new byte[2];
+ checkStatus(getParameter(PARAM_ROOM_LEVEL, param));
+ return byteArrayToShort(param);
+ }
+
+ /**
+ * Sets the volume level at 5 kHz relative to the volume level at low frequencies of the
+ * overall reverb effect.
+ * <p>This controls a low-pass filter that will reduce the level of the high-frequency.
+ * @param roomHF High frequency attenuation level in millibels. The valid range is [-9000, 0].
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public void setRoomHFLevel(short roomHF)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ byte[] param = shortToByteArray(roomHF);
+ checkStatus(setParameter(PARAM_ROOM_HF_LEVEL, param));
+ }
+
+ /**
+ * Gets the room HF level.
+ * @return the room HF level in millibels.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public short getRoomHFLevel()
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ byte[] param = new byte[2];
+ checkStatus(getParameter(PARAM_ROOM_HF_LEVEL, param));
+ return byteArrayToShort(param);
+ }
+
+ /**
+ * Sets the time taken for the level of reverberation to decay by 60 dB.
+ * @param decayTime Decay time in milliseconds. The valid range is [100, 20000].
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public void setDecayTime(int decayTime)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ byte[] param = intToByteArray(decayTime);
+ checkStatus(setParameter(PARAM_DECAY_TIME, param));
+ }
+
+ /**
+ * Gets the decay time.
+ * @return the decay time in milliseconds.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public int getDecayTime()
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ byte[] param = new byte[4];
+ checkStatus(getParameter(PARAM_DECAY_TIME, param));
+ return byteArrayToInt(param);
+ }
+
+ /**
+ * Sets the ratio of high frequency decay time (at 5 kHz) relative to the decay time at low
+ * frequencies.
+ * @param decayHFRatio High frequency decay ratio using a permille scale. The valid range is
+ * [100, 2000]. A ratio of 1000 indicates that all frequencies decay at the same rate.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public void setDecayHFRatio(short decayHFRatio)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ byte[] param = shortToByteArray(decayHFRatio);
+ checkStatus(setParameter(PARAM_DECAY_HF_RATIO, param));
+ }
+
+ /**
+ * Gets the ratio of high frequency decay time (at 5 kHz) relative to low frequencies.
+ * @return the decay HF ration. See {@link #setDecayHFRatio(short)} for units.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public short getDecayHFRatio()
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ byte[] param = new byte[2];
+ checkStatus(getParameter(PARAM_DECAY_HF_RATIO, param));
+ return byteArrayToShort(param);
+ }
+
+ /**
+ * Sets the volume level of the early reflections.
+ * <p>This level is combined with the overall room level
+ * (set using {@link #setRoomLevel(short)}).
+ * @param reflectionsLevel Reflection level in millibels. The valid range is [-9000, 1000].
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public void setReflectionsLevel(short reflectionsLevel)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ byte[] param = shortToByteArray(reflectionsLevel);
+ checkStatus(setParameter(PARAM_REFLECTIONS_LEVEL, param));
+ }
+
+ /**
+ * Gets the volume level of the early reflections.
+ * @return the early reflections level in millibels.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public short getReflectionsLevel()
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ byte[] param = new byte[2];
+ checkStatus(getParameter(PARAM_REFLECTIONS_LEVEL, param));
+ return byteArrayToShort(param);
+ }
+
+ /**
+ * Sets the delay time for the early reflections.
+ * <p>This method sets the time between when the direct path is heard and when the first
+ * reflection is heard.
+ * @param reflectionsDelay Reflections delay in milliseconds. The valid range is [0, 300].
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public void setReflectionsDelay(int reflectionsDelay)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ byte[] param = intToByteArray(reflectionsDelay);
+ checkStatus(setParameter(PARAM_REFLECTIONS_DELAY, param));
+ }
+
+ /**
+ * Gets the reflections delay.
+ * @return the early reflections delay in milliseconds.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public int getReflectionsDelay()
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ byte[] param = new byte[4];
+ checkStatus(getParameter(PARAM_REFLECTIONS_DELAY, param));
+ return byteArrayToInt(param);
+ }
+
+ /**
+ * Sets the volume level of the late reverberation.
+ * <p>This level is combined with the overall room level (set using {@link #setRoomLevel(short)}).
+ * @param reverbLevel Reverb level in millibels. The valid range is [-9000, 2000].
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public void setReverbLevel(short reverbLevel)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ byte[] param = shortToByteArray(reverbLevel);
+ checkStatus(setParameter(PARAM_REVERB_LEVEL, param));
+ }
+
+ /**
+ * Gets the reverb level.
+ * @return the reverb level in millibels.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public short getReverbLevel()
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ byte[] param = new byte[2];
+ checkStatus(getParameter(PARAM_REVERB_LEVEL, param));
+ return byteArrayToShort(param);
+ }
+
+ /**
+ * Sets the time between the first reflection and the reverberation.
+ * @param reverbDelay Reverb delay in milliseconds. The valid range is [0, 100].
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public void setReverbDelay(int reverbDelay)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ byte[] param = intToByteArray(reverbDelay);
+ checkStatus(setParameter(PARAM_REVERB_DELAY, param));
+ }
+
+ /**
+ * Gets the reverb delay.
+ * @return the reverb delay in milliseconds.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public int getReverbDelay()
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ byte[] param = new byte[4];
+ checkStatus(getParameter(PARAM_REVERB_DELAY, param));
+ return byteArrayToInt(param);
+ }
+
+ /**
+ * Sets the echo density in the late reverberation decay.
+ * <p>The scale should approximately map linearly to the perceived change in reverberation.
+ * @param diffusion Diffusion specified using a permille scale. The diffusion valid range is
+ * [0, 1000]. A value of 1000 o/oo indicates a smooth reverberation decay.
+ * Values below this level give a more <i>grainy</i> character.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public void setDiffusion(short diffusion)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ byte[] param = shortToByteArray(diffusion);
+ checkStatus(setParameter(PARAM_DIFFUSION, param));
+ }
+
+ /**
+ * Gets diffusion level.
+ * @return the diffusion level. See {@link #setDiffusion(short)} for units.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public short getDiffusion()
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ byte[] param = new byte[2];
+ checkStatus(getParameter(PARAM_DIFFUSION, param));
+ return byteArrayToShort(param);
+ }
+
+
+ /**
+ * Controls the modal density of the late reverberation decay.
+ * <p> The scale should approximately map linearly to the perceived change in reverberation.
+ * A lower density creates a hollow sound that is useful for simulating small reverberation
+ * spaces such as bathrooms.
+ * @param density Density specified using a permille scale. The valid range is [0, 1000].
+ * A value of 1000 o/oo indicates a natural sounding reverberation. Values below this level
+ * produce a more colored effect.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public void setDensity(short density)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ byte[] param = shortToByteArray(density);
+ checkStatus(setParameter(PARAM_DENSITY, param));
+ }
+
+ /**
+ * Gets the density level.
+ * @return the density level. See {@link #setDiffusion(short)} for units.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public short getDensity()
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ byte[] param = new byte[2];
+ checkStatus(getParameter(PARAM_DENSITY, param));
+ return byteArrayToShort(param);
+ }
+
+
+ /**
+ * The OnParameterChangeListener interface defines a method called by the EnvironmentalReverb
+ * when a parameter value has changed.
+ */
+ public interface OnParameterChangeListener {
+ /**
+ * Method called when a parameter value has changed. The method is called only if the
+ * parameter was changed by another application having the control of the same
+ * EnvironmentalReverb engine.
+ * @param effect the EnvironmentalReverb on which the interface is registered.
+ * @param status status of the set parameter operation.
+ // TODO when AudioEffect is unhidden
+ // See {_at_link android.media.AudioEffect#setParameter(byte[], byte[])}.
+ * @param param ID of the modified parameter. See {@link #PARAM_ROOM_LEVEL} ...
+ * @param value the new parameter value.
+ */
+ void onParameterChange(EnvironmentalReverb effect, int status, int param, int value);
+ }
+
+ /**
+ * Listener used internally to receive unformatted parameter change events from AudioEffect
+ * super class.
+ */
+ private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+ private BaseParameterListener() {
+
+ }
+ public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+ OnParameterChangeListener l = null;
+
+ synchronized (mParamListenerLock) {
+ if (mParamListener != null) {
+ l = mParamListener;
+ }
+ }
+ if (l != null) {
+ int p = -1;
+ int v = -1;
+
+ if (param.length == 4) {
+ p = byteArrayToInt(param, 0);
+ }
+ if (value.length == 2) {
+ v = (int)byteArrayToShort(value, 0);
+ } else if (value.length == 4) {
+ v = byteArrayToInt(value, 0);
+ }
+ if (p != -1 && v != -1) {
+ l.onParameterChange(EnvironmentalReverb.this, status, p, v);
+ }
+ }
+ }
+ }
+
+ /**
+ * Registers an OnParameterChangeListener interface.
+ * @param listener OnParameterChangeListener interface registered
+ */
+ public void setParameterListener(OnParameterChangeListener listener) {
+ synchronized (mParamListenerLock) {
+ if (mParamListener == null) {
+ mParamListener = listener;
+ mBaseParamListener = new BaseParameterListener();
+ super.setParameterListener(mBaseParamListener);
+ }
+ }
+ }
+}
diff --git a/media/java/android/media/Equalizer.java b/media/java/android/media/Equalizer.java
new file mode 100644
index 0000000..082f694
--- /dev/null
+++ b/media/java/android/media/Equalizer.java
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2009 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 android.media;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+
+import android.media.AudioEffect;
+
+/**
+ * An Equalizer is used to alter the frequency response of a particular music source or of the main
+ * output mix.
+ * <p>An application creates an Equalizer object to instantiate and control an Equalizer engine
+ * in the audio framework. The application can either simply use predefined presets or have a more
+ * precise control of the gain in each frequency band controlled by the equalizer.
+ * <p>The methods, parameter types and units exposed by the Equalizer implementation are directly
+ * mapping those defined by the OpenSL ES 1.0.1 Specification (http://www.khronos.org/opensles/)
+ * for the SLEqualizerItf interface. Please refer to this specification for more details.
+ * <p>To attach the Equalizer to a particular AudioTrack or MediaPlayer, specify the audio session
+ * ID of this AudioTrack or MediaPlayer when constructing the Equalizer. If the audio session ID 0
+ * is specified, the Equalizer applies to the main audio output mix.
+ // TODO when AudioEffect is unhidden
+ // <p> See {_at_link android.media.AudioEffect} class for more details on controlling audio effects.
+ *
+ * {@hide Pending API council review}
+ */
+
+public class Equalizer extends AudioEffect {
+
+ private final static String TAG = "Equalizer";
+
+ // These constants must be synchronized with those in
+ // frameworks/base/include/media/EffectEqualizerApi.h
+ /**
+ * Number of bands. Parameter ID for {@link android.media.Equalizer.OnParameterChangeListener}
+ */
+ public static final int PARAM_NUM_BANDS = 0;
+ /**
+ * Band level range. Parameter ID for OnParameterChangeListener
+ */
+ public static final int PARAM_LEVEL_RANGE = 1;
+ /**
+ * Band level. Parameter ID for OnParameterChangeListener
+ */
+ public static final int PARAM_BAND_LEVEL = 2;
+ /**
+ * Band center frequency. Parameter ID for OnParameterChangeListener
+ */
+ public static final int PARAM_CENTER_FREQ = 3;
+ /**
+ * Band frequency range. Parameter ID for OnParameterChangeListener
+ */
+ public static final int PARAM_BAND_FREQ_RANGE = 4;
+ /**
+ * Band for a given frequency. Parameter ID for OnParameterChangeListener
+ */
+ public static final int PARAM_GET_BAND = 5;
+ /**
+ * Current preset. Parameter ID for OnParameterChangeListener
+ */
+ public static final int PARAM_CURRENT_PRESET = 6;
+ /**
+ * Request number of presets. Parameter ID for OnParameterChangeListener
+ */
+ public static final int PARAM_GET_NUM_OF_PRESETS = 7;
+ /**
+ * Request preset name. Parameter ID for OnParameterChangeListener
+ */
+ public static final int PARAM_GET_PRESET_NAME = 8;
+ /**
+ * maximum size for perset name
+ */
+ public static final int PARAM_STRING_SIZE_MAX = 32;
+
+ /**
+ * Number of presets implemented by Equalizer engine
+ */
+ private int mNumPresets;
+ /**
+ * Names of presets implemented by Equalizer engine
+ */
+ private String[] mPresetNames;
+
+ /**
+ * Registered listener for parameter changes.
+ */
+ private OnParameterChangeListener mParamListener = null;
+
+ /**
+ * Listener used internally to to receive raw parameter change event from AudioEffect super class
+ */
+ private BaseParameterListener mBaseParamListener = null;
+
+ /**
+ * Lock for access to mParamListener
+ */
+ private final Object mParamListenerLock = new Object();
+
+ /**
+ * Class constructor.
+ * @param priority the priority level requested by the application for controlling the Equalizer
+ * engine. As the same engine can be shared by several applications, this parameter indicates
+ * how much the requesting application needs control of effect parameters. The normal priority
+ * is 0, above normal is a positive number, below normal a negative number.
+ * @param audioSession System wide unique audio session identifier. If audioSession
+ * is not 0, the Equalizer will be attached to the MediaPlayer or AudioTrack in the
+ * same audio session. Otherwise, the Equalizer will apply to the output mix.
+ *
+ * @throws java.lang.IllegalStateException
+ * @throws java.lang.IllegalArgumentException
+ * @throws java.lang.UnsupportedOperationException
+ * @throws java.lang.RuntimeException
+ */
+ public Equalizer(int priority, int audioSession)
+ throws IllegalStateException, IllegalArgumentException,
+ UnsupportedOperationException, RuntimeException {
+ super(EFFECT_TYPE_EQUALIZER, EFFECT_TYPE_NULL, priority, audioSession);
+
+ mNumPresets = (int)getNumberOfPresets();
+
+ if (mNumPresets != 0) {
+ mPresetNames = new String[mNumPresets];
+ byte[] value = new byte[PARAM_STRING_SIZE_MAX];
+ int[] param = new int[2];
+ param[0] = PARAM_GET_PRESET_NAME;
+ for (int i = 0; i < mNumPresets; i++) {
+ param[1] = i;
+ checkStatus(getParameter(param, value));
+ int length = 0;
+ while (value[length] != 0) length++;
+ try {
+ mPresetNames[i] = new String(value, 0, length, "ISO-8859-1");
+ Log.e(TAG, "preset #: "+i+" name: "+mPresetNames[i]+" length: "+length);
+ } catch (java.io.UnsupportedEncodingException e) {
+ Log.e(TAG, "preset name decode error");
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the number of frequency bands supported by the Equalizer engine.
+ * @return the number of bands
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public short getNumberOfBands()
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ int[] param = new int[1];
+ param[0] = PARAM_NUM_BANDS;
+ short[] value = new short[1];
+ checkStatus(getParameter(param, value));
+ return value[0];
+ }
+
+ /**
+ * Gets the level range for use by {@link #setBandLevel(int,short)}. The level is expressed in
+ * milliBel.
+ * @return the band level range in an array of short integers. The first element is the lower
+ * limit of the range, the second element the upper limit.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public short[] getBandLevelRange()
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ int[] param = new int[1];
+ int[] value = new int[2];
+ param[0] = PARAM_LEVEL_RANGE;
+ checkStatus(getParameter(param, value));
+
+ short[] result = new short[2];
+
+ result[0] = (short)value[0];
+ result[1] = (short)value[1];
+
+ return result;
+ }
+
+ /**
+ * Sets the given equalizer band to the given gain value.
+ * @param band Frequency band that will have the new gain. The numbering of the bands starts
+ * from 0 and ends at (number of bands - 1). See @see #getNumberOfBands().
+ * @param level New gain in millibels that will be set to the given band. getBandLevelRange()
+ * will define the maximum and minimum values.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public void setBandLevel(int band, short level)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ int[] param = new int[2];
+ int[] value = new int[1];
+
+ param[0] = PARAM_BAND_LEVEL;
+ param[1] = band;
+ value[0] = (int)level;
+ checkStatus(setParameter(param, value));
+ }
+
+ /**
+ * Gets the gain set for the given equalizer band.
+ * @param band Frequency band whose gain is requested. The numbering of the bands starts
+ * from 0 and ends at (number of bands - 1).
+ * @return Gain in millibels of the given band.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public short getBandLevel(int band)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ int[] param = new int[2];
+ int[] result = new int[1];
+
+ param[0] = PARAM_BAND_LEVEL;
+ param[1] = band;
+ checkStatus(getParameter(param, result));
+
+ return (short)result[0];
+ }
+
+
+ /**
+ * Gets the center frequency of the given band.
+ * @param band Frequency band whose center frequency is requested. The numbering of the bands
+ * starts from 0 and ends at (number of bands - 1).
+ * @return The center frequency in milliHertz
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public int getCenterFreq(int band)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ int[] param = new int[2];
+ int[] result = new int[1];
+
+ param[0] = PARAM_CENTER_FREQ;
+ param[1] = band;
+ checkStatus(getParameter(param, result));
+
+ return result[0];
+ }
+
+ /**
+ * Gets the frequency range of the given frequency band.
+ * @param band Frequency band whose frequency range is requested. The numbering of the bands
+ * starts from 0 and ends at (number of bands - 1).
+ * @return The frequency range in millHertz in an array of integers. The first element is the
+ * lower limit of the range, the second element the upper limit.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public int[] getBandFreqRange(int band)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ int[] param = new int[2];
+ int[] result = new int[2];
+ param[0] = PARAM_BAND_FREQ_RANGE;
+ param[1] = band;
+ checkStatus(getParameter(param, result));
+
+ return result;
+ }
+
+ /**
+ * Gets the band that has the most effect on the given frequency.
+ * @param frequency Frequency in milliHertz which is to be equalized via the returned band.
+ * @return Frequency band that has most effect on the given frequency.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public int getBand(int frequency)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ int[] param = new int[2];
+ int[] result = new int[1];
+
+ param[0] = PARAM_GET_BAND;
+ param[1] = frequency;
+ checkStatus(getParameter(param, result));
+
+ return result[0];
+ }
+
+ /**
+ * Gets current preset.
+ * @return Preset that is set at the moment.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public short getCurrentPreset()
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ int[] param = new int[1];
+ param[0] = PARAM_CURRENT_PRESET;
+ short[] value = new short[1];
+ checkStatus(getParameter(param, value));
+ return value[0];
+ }
+
+ /**
+ * Sets the equalizer according to the given preset.
+ * @param preset New preset that will be taken into use. The valid range is [0,
+ * number of presets-1]. See {@see #getNumberOfPresets()}.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public void usePreset(short preset)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ checkStatus(setParameter(PARAM_CURRENT_PRESET, preset));
+ }
+
+ /**
+ * Gets the total number of presets the equalizer supports. The presets will have indices
+ * [0, number of presets-1].
+ * @return The number of presets the equalizer supports.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public short getNumberOfPresets()
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ int[] param = new int[1];
+ param[0] = PARAM_GET_NUM_OF_PRESETS;
+ short[] value = new short[1];
+ checkStatus(getParameter(param, value));
+ return value[0];
+ }
+
+ /**
+ * Gets the preset name based on the index.
+ * @param preset Index of the preset. The valid range is [0, number of presets-1].
+ * @return A string containing the name of the given preset.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public String getPresetName(short preset)
+ {
+ if (preset >= 0 && preset < mNumPresets) {
+ return mPresetNames[preset];
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * The OnParameterChangeListener interface defines a method called by the Equalizer when a
+ * parameter value has changed.
+ */
+ public interface OnParameterChangeListener {
+ /**
+ * Method called when a parameter value has changed. The method is called only if the
+ * parameter was changed by another application having the control of the same
+ * Equalizer engine.
+ * @param effect the Equalizer on which the interface is registered.
+ * @param status status of the set parameter operation.
+ // TODO when AudioEffect is unhidden
+ // See {_at_link android.media.AudioEffect#setParameter(byte[], byte[])}.
+ * @param param1 ID of the modified parameter. See {@link #PARAM_BAND_LEVEL} ...
+ * @param param2 additional parameter qualifier (e.g the band for band level parameter).
+ * @param value the new parameter value.
+ */
+ void onParameterChange(Equalizer effect, int status, int param1, int param2, int value);
+ }
+
+ /**
+ * Listener used internally to receive unformatted parameter change events from AudioEffect
+ * super class.
+ */
+ private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+ private BaseParameterListener() {
+
+ }
+ public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+ OnParameterChangeListener l = null;
+
+ synchronized (mParamListenerLock) {
+ if (mParamListener != null) {
+ l = mParamListener;
+ }
+ }
+ if (l != null) {
+ int p1 = -1;
+ int p2 = -1;
+ int v = -1;
+
+ if (param.length >= 4) {
+ p1 = byteArrayToInt(param, 0);
+ if (param.length >= 8) {
+ p2 = byteArrayToInt(param, 4);
+ }
+ }
+ if (value.length == 2) {
+ v = (int)byteArrayToShort(value, 0);;
+ } else if (value.length == 4) {
+ v = byteArrayToInt(value, 0);
+ }
+
+ if (p1 != -1 && v != -1) {
+ l.onParameterChange(Equalizer.this, status, p1, p2, v);
+ }
+ }
+ }
+ }
+
+ /**
+ * Registers an OnParameterChangeListener interface.
+ * @param listener OnParameterChangeListener interface registered
+ */
+ public void setParameterListener(OnParameterChangeListener listener) {
+ synchronized (mParamListenerLock) {
+ if (mParamListener == null) {
+ mParamListener = listener;
+ mBaseParamListener = new BaseParameterListener();
+ super.setParameterListener(mBaseParamListener);
+ }
+ }
+ }
+
+}
diff --git a/media/java/android/media/PresetReverb.java b/media/java/android/media/PresetReverb.java
new file mode 100644
index 0000000..83a01a4
--- /dev/null
+++ b/media/java/android/media/PresetReverb.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2009 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 android.media;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+
+import android.media.AudioEffect;
+
+/**
+ * A sound generated within a room travels in many directions. The listener first hears the
+ * direct sound from the source itself. Later, he or she hears discrete echoes caused by sound
+ * bouncing off nearby walls, the ceiling and the floor. As sound waves arrive after
+ * undergoing more and more reflections, individual reflections become indistinguishable and
+ * the listener hears continuous reverberation that decays over time.
+ * Reverb is vital for modeling a listener's environment. It can be used in music applications
+ * to simulate music being played back in various environments, or in games to immerse the
+ * listener within the game's environment.
+ * The PresetReverb class allows an application to configure the global reverb using a reverb preset.
+ * This is primarily used for adding some reverb in a music playback context. Applications
+ * requiring control over a more advanced environmental reverb are advised to use the
+ // TODO when EnvironmentalReverb is unhidden
+ // {_at_link android.media.EnvironmentalReverb} class.
+ * <p>An application creates a PresetReverb object to instantiate and control a reverb engine in the
+ * audio framework.
+ * <p>The methods, parameter types and units exposed by the PresetReverb implementation are
+ * directly mapping those defined by the OpenSL ES 1.0.1 Specification
+ * (http://www.khronos.org/opensles/) for the SLPresetReverbItf interface.
+ * Please refer to this specification for more details.
+ * <p>The PresetReverb is an output mix auxiliary effect and should be created on
+ * Audio session 0. In order for a MediaPlayer or AudioTrack to be fed into this effect,
+ * they must be explicitely attached to it and a send level must be specified. Use the effect ID
+ * returned by getId() method to designate this particular effect when attaching it to the
+ * MediaPlayer or AudioTrack.
+ // TODO when AudioEffect is unhidden
+ // <p> See {_at_link android.media.AudioEffect} class for more details on controlling audio effects.
+ *
+ * {@hide Pending API council review}
+ */
+
+public class PresetReverb extends AudioEffect {
+
+ private final static String TAG = "PresetReverb";
+
+ // These constants must be synchronized with those in
+ // frameworks/base/include/media/EffectPresetReverbApi.h
+
+ /**
+ * Preset. Parameter ID for
+ * {@link android.media.PresetReverb.OnParameterChangeListener}
+ */
+ public static final int PARAM_PRESET = 0;
+
+ /**
+ * Room level. Parameter ID for
+ * {@link android.media.PresetReverb.OnParameterChangeListener}
+ */
+ public static final int PRESET_NONE = 0;
+ public static final int PRESET_SMALLROOM = 1;
+ public static final int PRESET_MEDIUMROOM = 2;
+ public static final int PRESET_LARGEROOM = 3;
+ public static final int PRESET_MEDIUMHALL = 4;
+ public static final int PRESET_LARGEHALL = 5;
+ public static final int PRESET_PLATE = 6;
+
+ /**
+ * Registered listener for parameter changes.
+ */
+ private OnParameterChangeListener mParamListener = null;
+
+ /**
+ * Listener used internally to to receive raw parameter change event from AudioEffect super class
+ */
+ private BaseParameterListener mBaseParamListener = null;
+
+ /**
+ * Lock for access to mParamListener
+ */
+ private final Object mParamListenerLock = new Object();
+
+ /**
+ * Class constructor.
+ * @param priority the priority level requested by the application for controlling the
+ * PresetReverb engine. As the same engine can be shared by several applications, this
+ * parameter indicates how much the requesting application needs control of effect parameters.
+ * The normal priority is 0, above normal is a positive number, below normal a negative number.
+ * @param audioSession System wide unique audio session identifier. If audioSession
+ * is not 0, the PresetReverb will be attached to the MediaPlayer or AudioTrack in the
+ * same audio session. Otherwise, the PresetReverb will apply to the output mix.
+ * As the PresetReverb is an auxiliary effect it is recommended to instantiate it on
+ * audio session 0 and to attach it to the MediaPLayer auxiliary output.
+ *
+ * @throws java.lang.IllegalArgumentException
+ * @throws java.lang.UnsupportedOperationException
+ * @throws java.lang.RuntimeException
+ */
+ public PresetReverb(int priority, int audioSession)
+ throws IllegalArgumentException, UnsupportedOperationException, RuntimeException {
+ super(EFFECT_TYPE_PRESET_REVERB, EFFECT_TYPE_NULL, priority, audioSession);
+ Log.e(TAG, "contructor");
+ }
+
+ /**
+ * Enables a preset on the reverb.
+ * <p>The reverb PRESET_NONE disables any reverb from the current output but does not free the
+ * resources associated with the reverb. For an application to signal to the implementation
+ * to free the resources, it must call the release() method.
+ * @param preset This must be one of the the preset constants defined in this class.
+ * e.g. {@link #PRESET_SMALLROOM}
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public void setPreset(short preset)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ checkStatus(setParameter(PARAM_PRESET, preset));
+ }
+
+ /**
+ * Gets current reverb preset.
+ * @return Preset that is set at the moment.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public short getPreset()
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ int[] param = new int[1];
+ param[0] = PARAM_PRESET;
+ short[] value = new short[1];
+ checkStatus(getParameter(param, value));
+ return value[0];
+ }
+
+ /**
+ * The OnParameterChangeListener interface defines a method called by the PresetReverb
+ * when a parameter value has changed.
+ */
+ public interface OnParameterChangeListener {
+ /**
+ * Method called when a parameter value has changed. The method is called only if the
+ * parameter was changed by another application having the control of the same
+ * PresetReverb engine.
+ * @param effect the PresetReverb on which the interface is registered.
+ * @param status status of the set parameter operation.
+ // TODO when AudioEffect is unhidden
+ // See {_at_link android.media.AudioEffect#setParameter(byte[], byte[])}.
+ * @param param ID of the modified parameter. See {@link #PARAM_PRESET} ...
+ * @param value the new parameter value.
+ */
+ void onParameterChange(PresetReverb effect, int status, int param, short value);
+ }
+
+ /**
+ * Listener used internally to receive unformatted parameter change events from AudioEffect
+ * super class.
+ */
+ private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+ private BaseParameterListener() {
+
+ }
+ public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+ OnParameterChangeListener l = null;
+
+ synchronized (mParamListenerLock) {
+ if (mParamListener != null) {
+ l = mParamListener;
+ }
+ }
+ if (l != null) {
+ int p = -1;
+ short v = -1;
+
+ if (param.length == 4) {
+ p = byteArrayToInt(param, 0);
+ }
+ if (value.length == 2) {
+ v = byteArrayToShort(value, 0);
+ }
+ if (p != -1 && v != -1) {
+ l.onParameterChange(PresetReverb.this, status, p, v);
+ }
+ }
+ }
+ }
+
+ /**
+ * Registers an OnParameterChangeListener interface.
+ * @param listener OnParameterChangeListener interface registered
+ */
+ public void setParameterListener(OnParameterChangeListener listener) {
+ synchronized (mParamListenerLock) {
+ if (mParamListener == null) {
+ mParamListener = listener;
+ mBaseParamListener = new BaseParameterListener();
+ super.setParameterListener(mBaseParamListener);
+ }
+ }
+ }
+}
diff --git a/media/java/android/media/Virtualizer.java b/media/java/android/media/Virtualizer.java
new file mode 100644
index 0000000..9f71297
--- /dev/null
+++ b/media/java/android/media/Virtualizer.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2009 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 android.media;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+
+import android.media.AudioEffect;
+
+/**
+ * An audio virtualizer is a general name for an effect to spatialize audio channels. The exact
+ * behavior of this effect is dependent on the number of audio input channels and the types and
+ * number of audio output channels of the device. For example, in the case of a stereo input and
+ * stereo headphone output, a stereo widening effect is used when this effect is turned on.
+ * <p>An application creates a Virtualizer object to instantiate and control a virtualizer engine
+ * in the audio framework.
+ * <p>The methods, parameter types and units exposed by the Virtualizer implementation are directly
+ * mapping those defined by the OpenSL ES 1.0.1 Specification (http://www.khronos.org/opensles/)
+ * for the SLVirtualizerItf interface. Please refer to this specification for more details.
+ * <p>To attach the Virtualizer to a particular AudioTrack or MediaPlayer, specify the audio session
+ * ID of this AudioTrack or MediaPlayer when constructing the Virtualizer. If the audio session ID 0
+ * is specified, the Virtualizer applies to the main audio output mix.
+ // TODO when AudioEffect is unhidden
+ // <p> See {_at_link android.media.AudioEffect} class for more details on controlling audio effects.
+ *
+ * {@hide Pending API council review}
+ */
+
+public class Virtualizer extends AudioEffect {
+
+ private final static String TAG = "Virtualizer";
+
+ // These constants must be synchronized with those in frameworks/base/include/media/EffectVirtualizerApi.h
+ /**
+ * Is strength parameter supported by virtualizer engine. Parameter ID for getParameter().
+ */
+ public static final int PARAM_STRENGTH_SUPPORTED = 0;
+ /**
+ * Virtualizer effect strength. Parameter ID for
+ * {@link android.media.Virtualizer.OnParameterChangeListener}
+ */
+ public static final int PARAM_STRENGTH = 1;
+
+ /**
+ * Indicates if strength parameter is supported by the virtualizer engine
+ */
+ private boolean mStrengthSupported = false;
+
+ /**
+ * Registered listener for parameter changes.
+ */
+ private OnParameterChangeListener mParamListener = null;
+
+ /**
+ * Listener used internally to to receive raw parameter change event from AudioEffect super class
+ */
+ private BaseParameterListener mBaseParamListener = null;
+
+ /**
+ * Lock for access to mParamListener
+ */
+ private final Object mParamListenerLock = new Object();
+
+ /**
+ * Class constructor.
+ * @param priority the priority level requested by the application for controlling the Virtualizer
+ * engine. As the same engine can be shared by several applications, this parameter indicates
+ * how much the requesting application needs control of effect parameters. The normal priority
+ * is 0, above normal is a positive number, below normal a negative number.
+ * @param audioSession System wide unique audio session identifier. If audioSession
+ * is not 0, the Virtualizer will be attached to the MediaPlayer or AudioTrack in the
+ * same audio session. Otherwise, the Virtualizer will apply to the output mix.
+ *
+ * @throws java.lang.IllegalStateException
+ * @throws java.lang.IllegalArgumentException
+ * @throws java.lang.UnsupportedOperationException
+ * @throws java.lang.RuntimeException
+ */
+ public Virtualizer(int priority, int audioSession)
+ throws IllegalStateException, IllegalArgumentException,
+ UnsupportedOperationException, RuntimeException {
+ super(EFFECT_TYPE_VIRTUALIZER, EFFECT_TYPE_NULL, priority, audioSession);
+
+ short[] value = new short[1];
+ checkStatus(getParameter(PARAM_STRENGTH_SUPPORTED, value));
+ mStrengthSupported = (value[0] != 0);
+ }
+
+ /**
+ * Indicates whether setting strength is supported. If this method returns false, only one
+ * strength is supported and the setStrength() method always rounds to that value.
+ * @return true is strength parameter is supported, false otherwise
+ */
+ public boolean getStrengthSupported() {
+ return mStrengthSupported;
+ }
+
+ /**
+ * Sets the strength of the virtualizer effect. If the implementation does not support per mille
+ * accuracy for setting the strength, it is allowed to round the given strength to the nearest
+ * supported value. You can use the {@link #getRoundedStrength()} method to query the
+ * (possibly rounded) value that was actually set.
+ * @param strength Strength of the effect. The valid range for strength strength is [0, 1000],
+ * where 0 per mille designates the mildest effect and 1000 per mille designates the strongest.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public void setStrength(short strength)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ checkStatus(setParameter(PARAM_STRENGTH, strength));
+ }
+
+ /**
+ * Gets the current strength of the effect.
+ * @return The strength of the effect. The valid range for strength is [0, 1000], where 0 per
+ * mille designates the mildest effect and 1000 per mille the strongest
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public short getRoundedStrength()
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ short[] value = new short[1];
+ checkStatus(getParameter(PARAM_STRENGTH, value));
+ return value[0];
+ }
+
+ /**
+ * The OnParameterChangeListener interface defines a method called by the Virtualizer when a
+ * parameter value has changed.
+ */
+ public interface OnParameterChangeListener {
+ /**
+ * Method called when a parameter value has changed. The method is called only if the
+ * parameter was changed by another application having the control of the same
+ * Virtualizer engine.
+ * @param effect the Virtualizer on which the interface is registered.
+ * @param status status of the set parameter operation.
+ // TODO when AudioEffect is unhidden
+ // See {_at_link android.media.AudioEffect#setParameter(byte[], byte[])}.
+ * @param param ID of the modified parameter. See {@link #PARAM_STRENGTH} ...
+ * @param value the new parameter value.
+ */
+ void onParameterChange(Virtualizer effect, int status, int param, short value);
+ }
+
+ /**
+ * Listener used internally to receive unformatted parameter change events from AudioEffect
+ * super class.
+ */
+ private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+ private BaseParameterListener() {
+
+ }
+ public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+ OnParameterChangeListener l = null;
+
+ synchronized (mParamListenerLock) {
+ if (mParamListener != null) {
+ l = mParamListener;
+ }
+ }
+ if (l != null) {
+ int p = -1;
+ short v = -1;
+
+ if (param.length == 4) {
+ p = byteArrayToInt(param, 0);
+ }
+ if (value.length == 2) {
+ v = byteArrayToShort(value, 0);
+ }
+ if (p != -1 && v != -1) {
+ l.onParameterChange(Virtualizer.this, status, p, v);
+ }
+ }
+ }
+ }
+
+ /**
+ * Registers an OnParameterChangeListener interface.
+ * @param listener OnParameterChangeListener interface registered
+ */
+ public void setParameterListener(OnParameterChangeListener listener) {
+ synchronized (mParamListenerLock) {
+ if (mParamListener == null) {
+ mParamListener = listener;
+ mBaseParamListener = new BaseParameterListener();
+ super.setParameterListener(mBaseParamListener);
+ }
+ }
+ }
+}
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index 02474a4..beb3dfc 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -323,8 +323,8 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t
priority,
effectCallback,
&lpJniStorage->mCallbackData,
- 0,
- sessionId);
+ sessionId,
+ 0);
if (lpAudioEffect == NULL) {
LOGE("Error creating AudioEffect");
goto setup_failure;
diff --git a/media/libeffects/EffectReverb.c b/media/libeffects/EffectReverb.c
index ada252c..5c87f23 100644
--- a/media/libeffects/EffectReverb.c
+++ b/media/libeffects/EffectReverb.c
@@ -57,7 +57,7 @@ static const effect_descriptor_t gInsertEnvReverbDescriptor = {
// Google auxiliary preset reverb UUID: 63909320-53a6-11df-bdbd-0002a5d5c51b
static const effect_descriptor_t gAuxPresetReverbDescriptor = {
- {0x47382d60, 0xddd8, 0x4763, 0x11db, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
{0x63909320, 0x53a6, 0x11df, 0xbdbd, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
EFFECT_API_VERSION,
EFFECT_FLAG_TYPE_AUXILIARY,
@@ -69,7 +69,7 @@ static const effect_descriptor_t gAuxPresetReverbDescriptor = {
// Google insert preset reverb UUID: d93dc6a0-6342-11df-b128-0002a5d5c51b
static const effect_descriptor_t gInsertPresetReverbDescriptor = {
- {0x47382d60, 0xddd8, 0x4763, 0x11db, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
{0xd93dc6a0, 0x6342, 0x11df, 0xb128, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
EFFECT_API_VERSION,
EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST,
@@ -196,7 +196,7 @@ static int Reverb_Process(effect_interface_t self, audio_buffer_t *inBuffer, aud
pReverb = (reverb_object_t*) &pRvbModule->context;
//if bypassed or the preset forces the signal to be completely dry
- if (pReverb->m_bBypass) {
+ if (pReverb->m_bBypass != 0) {
if (inBuffer->raw != outBuffer->raw) {
int16_t smp;
pSrc = inBuffer->s16;
@@ -520,7 +520,7 @@ int Reverb_Configure(reverb_module_t *pRvbModule, effect_config_t *pConfig,
pReverb->m_bUseNoise = true;
// for debugging purposes, allow bypass
- pReverb->m_bBypass = false;
+ pReverb->m_bBypass = 0;
pReverb->m_nNextRoom = 1;
@@ -662,248 +662,254 @@ int Reverb_getParameter(reverb_object_t *pReverb, int32_t param, size_t *pSize,
int32_t temp2;
size_t size;
- if (pReverb->m_Preset && param != REVERB_PARAM_PRESET) {
- return -EINVAL;
- }
- if (!pReverb->m_Preset && param == REVERB_PARAM_PRESET) {
- return -EINVAL;
- }
-
- switch (param) {
- case REVERB_PARAM_ROOM_LEVEL:
- case REVERB_PARAM_ROOM_HF_LEVEL:
- case REVERB_PARAM_DECAY_HF_RATIO:
- case REVERB_PARAM_REFLECTIONS_LEVEL:
- case REVERB_PARAM_REVERB_LEVEL:
- case REVERB_PARAM_DIFFUSION:
- case REVERB_PARAM_DENSITY:
+ if (pReverb->m_Preset) {
+ if (param != REVERB_PARAM_PRESET || *pSize < sizeof(int16_t)) {
+ return -EINVAL;
+ }
size = sizeof(int16_t);
- break;
-
- case REVERB_PARAM_BYPASS:
- case REVERB_PARAM_PRESET:
- case REVERB_PARAM_DECAY_TIME:
- case REVERB_PARAM_REFLECTIONS_DELAY:
- case REVERB_PARAM_REVERB_DELAY:
- size = sizeof(int32_t);
- break;
-
- case REVERB_PARAM_PROPERTIES:
- size = sizeof(t_reverb_properties);
- break;
-
- default:
- return -EINVAL;
- }
+ pValue16 = (int16_t *)pValue;
+ // REVERB_PRESET_NONE is mapped to bypass
+ if (pReverb->m_bBypass != 0) {
+ *pValue16 = (int16_t)REVERB_PRESET_NONE;
+ } else {
+ *pValue16 = (int16_t)(pReverb->m_nNextRoom + 1);
+ }
+ LOGV("get REVERB_PARAM_PRESET, preset %d", *pValue16);
+ } else {
+ switch (param) {
+ case REVERB_PARAM_ROOM_LEVEL:
+ case REVERB_PARAM_ROOM_HF_LEVEL:
+ case REVERB_PARAM_DECAY_HF_RATIO:
+ case REVERB_PARAM_REFLECTIONS_LEVEL:
+ case REVERB_PARAM_REVERB_LEVEL:
+ case REVERB_PARAM_DIFFUSION:
+ case REVERB_PARAM_DENSITY:
+ size = sizeof(int16_t);
+ break;
- if (*pSize < size) {
- return -EINVAL;
- }
- *pSize = size;
- pValue32 = (int32_t *) pValue;
- pValue16 = (int16_t *) pValue;
- pProperties = (t_reverb_properties *) pValue;
+ case REVERB_PARAM_BYPASS:
+ case REVERB_PARAM_DECAY_TIME:
+ case REVERB_PARAM_REFLECTIONS_DELAY:
+ case REVERB_PARAM_REVERB_DELAY:
+ size = sizeof(int32_t);
+ break;
- switch (param) {
- case REVERB_PARAM_BYPASS:
- *(int32_t *) pValue = (int32_t) pReverb->m_bBypass;
- break;
- case REVERB_PARAM_PRESET:
- *(int32_t *) pValue = (int8_t) pReverb->m_nCurrentRoom;
- break;
+ case REVERB_PARAM_PROPERTIES:
+ size = sizeof(t_reverb_properties);
+ break;
- case REVERB_PARAM_PROPERTIES:
- pValue16 = &pProperties->roomLevel;
- /* FALL THROUGH */
+ default:
+ return -EINVAL;
+ }
- case REVERB_PARAM_ROOM_LEVEL:
- // Convert m_nRoomLpfFwd to millibels
- temp = (pReverb->m_nRoomLpfFwd << 15)
- / (32767 - pReverb->m_nRoomLpfFbk);
- *pValue16 = Effects_Linear16ToMillibels(temp);
+ if (*pSize < size) {
+ return -EINVAL;
+ }
- LOGV("get REVERB_PARAM_ROOM_LEVEL %d, gain %d, m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", *pValue16, temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
+ pValue32 = (int32_t *) pValue;
+ pValue16 = (int16_t *) pValue;
+ pProperties = (t_reverb_properties *) pValue;
- if (param == REVERB_PARAM_ROOM_LEVEL) {
- break;
- }
- pValue16 = &pProperties->roomHFLevel;
- /* FALL THROUGH */
-
- case REVERB_PARAM_ROOM_HF_LEVEL:
- // The ratio between linear gain at 0Hz and at 5000Hz for the room low pass is:
- // (1 + a1) / sqrt(a1^2 + 2*C*a1 + 1) where:
- // - a1 is minus the LP feedback gain: -pReverb->m_nRoomLpfFbk
- // - C is cos(2piWT) @ 5000Hz: pReverb->m_nCosWT_5KHz
-
- temp = MULT_EG1_EG1(pReverb->m_nRoomLpfFbk, pReverb->m_nRoomLpfFbk);
- LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, a1^2 %d", temp);
- temp2 = MULT_EG1_EG1(pReverb->m_nRoomLpfFbk, pReverb->m_nCosWT_5KHz)
- << 1;
- LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, 2 Cos a1 %d", temp2);
- temp = 32767 + temp - temp2;
- LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, a1^2 + 2 Cos a1 + 1 %d", temp);
- temp = Effects_Sqrt(temp) * 181;
- LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, SQRT(a1^2 + 2 Cos a1 + 1) %d", temp);
- temp = ((32767 - pReverb->m_nRoomLpfFbk) << 15) / temp;
-
- LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, gain %d, m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
-
- *pValue16 = Effects_Linear16ToMillibels(temp);
-
- if (param == REVERB_PARAM_ROOM_HF_LEVEL) {
+ switch (param) {
+ case REVERB_PARAM_BYPASS:
+ *pValue32 = (int32_t) pReverb->m_bBypass;
break;
- }
- pValue32 = &pProperties->decayTime;
- /* FALL THROUGH */
- case REVERB_PARAM_DECAY_TIME:
- // Calculate reverb feedback path gain
- temp = (pReverb->m_nRvbLpfFwd << 15) / (32767 - pReverb->m_nRvbLpfFbk);
- temp = Effects_Linear16ToMillibels(temp);
+ case REVERB_PARAM_PROPERTIES:
+ pValue16 = &pProperties->roomLevel;
+ /* FALL THROUGH */
- // Calculate decay time: g = -6000 d/DT , g gain in millibels, d reverb delay, DT decay time
- temp = (-6000 * pReverb->m_nLateDelay) / temp;
+ case REVERB_PARAM_ROOM_LEVEL:
+ // Convert m_nRoomLpfFwd to millibels
+ temp = (pReverb->m_nRoomLpfFwd << 15)
+ / (32767 - pReverb->m_nRoomLpfFbk);
+ *pValue16 = Effects_Linear16ToMillibels(temp);
- // Convert samples to ms
- *pValue32 = (temp * 1000) / pReverb->m_nSamplingRate;
+ LOGV("get REVERB_PARAM_ROOM_LEVEL %d, gain %d, m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", *pValue16, temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
- LOGV("get REVERB_PARAM_DECAY_TIME, samples %d, ms %d", temp, *pValue32);
-
- if (param == REVERB_PARAM_DECAY_TIME) {
- break;
- }
- pValue16 = &pProperties->decayHFRatio;
- /* FALL THROUGH */
-
- case REVERB_PARAM_DECAY_HF_RATIO:
- // If r is the decay HF ratio (r = REVERB_PARAM_DECAY_HF_RATIO/1000) we have:
- // DT_5000Hz = DT_0Hz * r
- // and G_5000Hz = -6000 * d / DT_5000Hz and G_0Hz = -6000 * d / DT_0Hz in millibels so :
- // r = G_0Hz/G_5000Hz in millibels
- // The linear gain at 5000Hz is b0 / sqrt(a1^2 + 2*C*a1 + 1) where:
- // - a1 is minus the LP feedback gain: -pReverb->m_nRvbLpfFbk
- // - b0 is the LP forward gain: pReverb->m_nRvbLpfFwd
- // - C is cos(2piWT) @ 5000Hz: pReverb->m_nCosWT_5KHz
- if (pReverb->m_nRvbLpfFbk == 0) {
- *pValue16 = 1000;
- LOGV("get REVERB_PARAM_DECAY_HF_RATIO, pReverb->m_nRvbLpfFbk == 0, ratio %d", *pValue16);
- } else {
- temp = MULT_EG1_EG1(pReverb->m_nRvbLpfFbk, pReverb->m_nRvbLpfFbk);
- temp2 = MULT_EG1_EG1(pReverb->m_nRvbLpfFbk, pReverb->m_nCosWT_5KHz)
+ if (param == REVERB_PARAM_ROOM_LEVEL) {
+ break;
+ }
+ pValue16 = &pProperties->roomHFLevel;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_ROOM_HF_LEVEL:
+ // The ratio between linear gain at 0Hz and at 5000Hz for the room low pass is:
+ // (1 + a1) / sqrt(a1^2 + 2*C*a1 + 1) where:
+ // - a1 is minus the LP feedback gain: -pReverb->m_nRoomLpfFbk
+ // - C is cos(2piWT) @ 5000Hz: pReverb->m_nCosWT_5KHz
+
+ temp = MULT_EG1_EG1(pReverb->m_nRoomLpfFbk, pReverb->m_nRoomLpfFbk);
+ LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, a1^2 %d", temp);
+ temp2 = MULT_EG1_EG1(pReverb->m_nRoomLpfFbk, pReverb->m_nCosWT_5KHz)
<< 1;
+ LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, 2 Cos a1 %d", temp2);
temp = 32767 + temp - temp2;
+ LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, a1^2 + 2 Cos a1 + 1 %d", temp);
temp = Effects_Sqrt(temp) * 181;
- temp = (pReverb->m_nRvbLpfFwd << 15) / temp;
- // The linear gain at 0Hz is b0 / (a1 + 1)
- temp2 = (pReverb->m_nRvbLpfFwd << 15) / (32767
- - pReverb->m_nRvbLpfFbk);
+ LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, SQRT(a1^2 + 2 Cos a1 + 1) %d", temp);
+ temp = ((32767 - pReverb->m_nRoomLpfFbk) << 15) / temp;
+
+ LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, gain %d, m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
+
+ *pValue16 = Effects_Linear16ToMillibels(temp);
+
+ if (param == REVERB_PARAM_ROOM_HF_LEVEL) {
+ break;
+ }
+ pValue32 = &pProperties->decayTime;
+ /* FALL THROUGH */
+ case REVERB_PARAM_DECAY_TIME:
+ // Calculate reverb feedback path gain
+ temp = (pReverb->m_nRvbLpfFwd << 15) / (32767 - pReverb->m_nRvbLpfFbk);
temp = Effects_Linear16ToMillibels(temp);
- temp2 = Effects_Linear16ToMillibels(temp2);
- LOGV("get REVERB_PARAM_DECAY_HF_RATIO, gain 5KHz %d mB, gain DC %d mB", temp, temp2);
- if (temp == 0)
- temp = 1;
- temp = (int16_t) ((1000 * temp2) / temp);
- if (temp > 1000)
- temp = 1000;
+ // Calculate decay time: g = -6000 d/DT , g gain in millibels, d reverb delay, DT decay time
+ temp = (-6000 * pReverb->m_nLateDelay) / temp;
- *pValue16 = temp;
- LOGV("get REVERB_PARAM_DECAY_HF_RATIO, ratio %d", *pValue16);
- }
+ // Convert samples to ms
+ *pValue32 = (temp * 1000) / pReverb->m_nSamplingRate;
- if (param == REVERB_PARAM_DECAY_HF_RATIO) {
- break;
- }
- pValue16 = &pProperties->reflectionsLevel;
- /* FALL THROUGH */
+ LOGV("get REVERB_PARAM_DECAY_TIME, samples %d, ms %d", temp, *pValue32);
- case REVERB_PARAM_REFLECTIONS_LEVEL:
- *pValue16 = Effects_Linear16ToMillibels(pReverb->m_nEarlyGain);
+ if (param == REVERB_PARAM_DECAY_TIME) {
+ break;
+ }
+ pValue16 = &pProperties->decayHFRatio;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_DECAY_HF_RATIO:
+ // If r is the decay HF ratio (r = REVERB_PARAM_DECAY_HF_RATIO/1000) we have:
+ // DT_5000Hz = DT_0Hz * r
+ // and G_5000Hz = -6000 * d / DT_5000Hz and G_0Hz = -6000 * d / DT_0Hz in millibels so :
+ // r = G_0Hz/G_5000Hz in millibels
+ // The linear gain at 5000Hz is b0 / sqrt(a1^2 + 2*C*a1 + 1) where:
+ // - a1 is minus the LP feedback gain: -pReverb->m_nRvbLpfFbk
+ // - b0 is the LP forward gain: pReverb->m_nRvbLpfFwd
+ // - C is cos(2piWT) @ 5000Hz: pReverb->m_nCosWT_5KHz
+ if (pReverb->m_nRvbLpfFbk == 0) {
+ *pValue16 = 1000;
+ LOGV("get REVERB_PARAM_DECAY_HF_RATIO, pReverb->m_nRvbLpfFbk == 0, ratio %d", *pValue16);
+ } else {
+ temp = MULT_EG1_EG1(pReverb->m_nRvbLpfFbk, pReverb->m_nRvbLpfFbk);
+ temp2 = MULT_EG1_EG1(pReverb->m_nRvbLpfFbk, pReverb->m_nCosWT_5KHz)
+ << 1;
+ temp = 32767 + temp - temp2;
+ temp = Effects_Sqrt(temp) * 181;
+ temp = (pReverb->m_nRvbLpfFwd << 15) / temp;
+ // The linear gain at 0Hz is b0 / (a1 + 1)
+ temp2 = (pReverb->m_nRvbLpfFwd << 15) / (32767
+ - pReverb->m_nRvbLpfFbk);
+
+ temp = Effects_Linear16ToMillibels(temp);
+ temp2 = Effects_Linear16ToMillibels(temp2);
+ LOGV("get REVERB_PARAM_DECAY_HF_RATIO, gain 5KHz %d mB, gain DC %d mB", temp, temp2);
+
+ if (temp == 0)
+ temp = 1;
+ temp = (int16_t) ((1000 * temp2) / temp);
+ if (temp > 1000)
+ temp = 1000;
+
+ *pValue16 = temp;
+ LOGV("get REVERB_PARAM_DECAY_HF_RATIO, ratio %d", *pValue16);
+ }
- LOGV("get REVERB_PARAM_REFLECTIONS_LEVEL, %d", *pValue16);
- if (param == REVERB_PARAM_REFLECTIONS_LEVEL) {
- break;
- }
- pValue32 = &pProperties->reflectionsDelay;
- /* FALL THROUGH */
+ if (param == REVERB_PARAM_DECAY_HF_RATIO) {
+ break;
+ }
+ pValue16 = &pProperties->reflectionsLevel;
+ /* FALL THROUGH */
- case REVERB_PARAM_REFLECTIONS_DELAY:
- // convert samples to ms
- *pValue32 = (pReverb->m_nEarlyDelay * 1000) / pReverb->m_nSamplingRate;
+ case REVERB_PARAM_REFLECTIONS_LEVEL:
+ *pValue16 = Effects_Linear16ToMillibels(pReverb->m_nEarlyGain);
- LOGV("get REVERB_PARAM_REFLECTIONS_DELAY, samples %d, ms %d", pReverb->m_nEarlyDelay, *pValue32);
+ LOGV("get REVERB_PARAM_REFLECTIONS_LEVEL, %d", *pValue16);
+ if (param == REVERB_PARAM_REFLECTIONS_LEVEL) {
+ break;
+ }
+ pValue32 = &pProperties->reflectionsDelay;
+ /* FALL THROUGH */
- if (param == REVERB_PARAM_REFLECTIONS_DELAY) {
- break;
- }
- pValue16 = &pProperties->reverbLevel;
- /* FALL THROUGH */
+ case REVERB_PARAM_REFLECTIONS_DELAY:
+ // convert samples to ms
+ *pValue32 = (pReverb->m_nEarlyDelay * 1000) / pReverb->m_nSamplingRate;
- case REVERB_PARAM_REVERB_LEVEL:
- // Convert linear gain to millibels
- *pValue16 = Effects_Linear16ToMillibels(pReverb->m_nLateGain << 2);
+ LOGV("get REVERB_PARAM_REFLECTIONS_DELAY, samples %d, ms %d", pReverb->m_nEarlyDelay, *pValue32);
- LOGV("get REVERB_PARAM_REVERB_LEVEL %d", *pValue16);
+ if (param == REVERB_PARAM_REFLECTIONS_DELAY) {
+ break;
+ }
+ pValue16 = &pProperties->reverbLevel;
+ /* FALL THROUGH */
- if (param == REVERB_PARAM_REVERB_LEVEL) {
- break;
- }
- pValue32 = &pProperties->reverbDelay;
- /* FALL THROUGH */
+ case REVERB_PARAM_REVERB_LEVEL:
+ // Convert linear gain to millibels
+ *pValue16 = Effects_Linear16ToMillibels(pReverb->m_nLateGain << 2);
- case REVERB_PARAM_REVERB_DELAY:
- // convert samples to ms
- *pValue32 = (pReverb->m_nLateDelay * 1000) / pReverb->m_nSamplingRate;
+ LOGV("get REVERB_PARAM_REVERB_LEVEL %d", *pValue16);
- LOGV("get REVERB_PARAM_REVERB_DELAY, samples %d, ms %d", pReverb->m_nLateDelay, *pValue32);
+ if (param == REVERB_PARAM_REVERB_LEVEL) {
+ break;
+ }
+ pValue32 = &pProperties->reverbDelay;
+ /* FALL THROUGH */
- if (param == REVERB_PARAM_REVERB_DELAY) {
- break;
- }
- pValue16 = &pProperties->diffusion;
- /* FALL THROUGH */
+ case REVERB_PARAM_REVERB_DELAY:
+ // convert samples to ms
+ *pValue32 = (pReverb->m_nLateDelay * 1000) / pReverb->m_nSamplingRate;
- case REVERB_PARAM_DIFFUSION:
- temp = (int16_t) ((1000 * (pReverb->m_sAp0.m_nApGain - AP0_GAIN_BASE))
- / AP0_GAIN_RANGE);
+ LOGV("get REVERB_PARAM_REVERB_DELAY, samples %d, ms %d", pReverb->m_nLateDelay, *pValue32);
- if (temp < 0)
- temp = 0;
- if (temp > 1000)
- temp = 1000;
+ if (param == REVERB_PARAM_REVERB_DELAY) {
+ break;
+ }
+ pValue16 = &pProperties->diffusion;
+ /* FALL THROUGH */
- *pValue16 = temp;
- LOGV("get REVERB_PARAM_DIFFUSION, %d, AP0 gain %d", *pValue16, pReverb->m_sAp0.m_nApGain);
+ case REVERB_PARAM_DIFFUSION:
+ temp = (int16_t) ((1000 * (pReverb->m_sAp0.m_nApGain - AP0_GAIN_BASE))
+ / AP0_GAIN_RANGE);
- if (param == REVERB_PARAM_DIFFUSION) {
- break;
- }
- pValue16 = &pProperties->density;
- /* FALL THROUGH */
+ if (temp < 0)
+ temp = 0;
+ if (temp > 1000)
+ temp = 1000;
- case REVERB_PARAM_DENSITY:
- // Calculate AP delay in time units
- temp = ((pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn) << 16)
- / pReverb->m_nSamplingRate;
+ *pValue16 = temp;
+ LOGV("get REVERB_PARAM_DIFFUSION, %d, AP0 gain %d", *pValue16, pReverb->m_sAp0.m_nApGain);
- temp = (int16_t) ((1000 * (temp - AP0_TIME_BASE)) / AP0_TIME_RANGE);
+ if (param == REVERB_PARAM_DIFFUSION) {
+ break;
+ }
+ pValue16 = &pProperties->density;
+ /* FALL THROUGH */
- if (temp < 0)
- temp = 0;
- if (temp > 1000)
- temp = 1000;
+ case REVERB_PARAM_DENSITY:
+ // Calculate AP delay in time units
+ temp = ((pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn) << 16)
+ / pReverb->m_nSamplingRate;
- *pValue16 = temp;
+ temp = (int16_t) ((1000 * (temp - AP0_TIME_BASE)) / AP0_TIME_RANGE);
- LOGV("get REVERB_PARAM_DENSITY, %d, AP0 delay smps %d", *pValue16, pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn);
- break;
+ if (temp < 0)
+ temp = 0;
+ if (temp > 1000)
+ temp = 1000;
- default:
- break;
+ *pValue16 = temp;
+
+ LOGV("get REVERB_PARAM_DENSITY, %d, AP0 delay smps %d", *pValue16, pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn);
+ break;
+
+ default:
+ break;
+ }
}
+ *pSize = size;
+
LOGV("Reverb_getParameter, context %p, param %d, value %d",
pReverb, param, *(int *)pValue);
@@ -945,382 +951,386 @@ int Reverb_setParameter(reverb_object_t *pReverb, int32_t param, size_t size,
LOGV("Reverb_setParameter, context %p, param %d, value16 %d, value32 %d",
pReverb, param, *(int16_t *)pValue, *(int32_t *)pValue);
- if (pReverb->m_Preset && param != REVERB_PARAM_PRESET) {
- return -EINVAL;
- }
- if (!pReverb->m_Preset && param == REVERB_PARAM_PRESET) {
- return -EINVAL;
- }
-
- switch (param) {
- case REVERB_PARAM_ROOM_LEVEL:
- case REVERB_PARAM_ROOM_HF_LEVEL:
- case REVERB_PARAM_DECAY_HF_RATIO:
- case REVERB_PARAM_REFLECTIONS_LEVEL:
- case REVERB_PARAM_REVERB_LEVEL:
- case REVERB_PARAM_DIFFUSION:
- case REVERB_PARAM_DENSITY:
- paramSize = sizeof(int16_t);
- break;
-
- case REVERB_PARAM_BYPASS:
- case REVERB_PARAM_PRESET:
- case REVERB_PARAM_DECAY_TIME:
- case REVERB_PARAM_REFLECTIONS_DELAY:
- case REVERB_PARAM_REVERB_DELAY:
- paramSize = sizeof(int32_t);
- break;
-
- case REVERB_PARAM_PROPERTIES:
- paramSize = sizeof(t_reverb_properties);
- break;
-
- default:
- return -EINVAL;
- }
-
- if (size != paramSize) {
- return -EINVAL;
- }
-
- if (paramSize == sizeof(int16_t)) {
- value16 = *(int16_t *) pValue;
- } else if (paramSize == sizeof(int32_t)) {
- value32 = *(int32_t *) pValue;
- } else {
- pProperties = (t_reverb_properties *) pValue;
- }
-
- pPreset = &pReverb->m_sPreset.m_sPreset[pReverb->m_nCurrentRoom];
-
- switch (param) {
- case REVERB_PARAM_BYPASS:
- pReverb->m_bBypass = (uint16_t)value32;
- break;
- case REVERB_PARAM_PRESET:
- if (value32 != REVERB_PRESET_LARGE_HALL && value32
- != REVERB_PRESET_HALL && value32 != REVERB_PRESET_CHAMBER
- && value32 != REVERB_PRESET_ROOM)
+ if (pReverb->m_Preset) {
+ if (param != REVERB_PARAM_PRESET || size != sizeof(int16_t)) {
return -EINVAL;
- pReverb->m_nNextRoom = (int16_t) value32;
- break;
-
- case REVERB_PARAM_PROPERTIES:
- value16 = pProperties->roomLevel;
- /* FALL THROUGH */
-
- case REVERB_PARAM_ROOM_LEVEL:
- // Convert millibels to linear 16 bit signed => m_nRoomLpfFwd
- if (value16 > 0)
+ }
+ value16 = *(int16_t *)pValue;
+ LOGV("set REVERB_PARAM_PRESET, preset %d", value16);
+ if (value16 < REVERB_PRESET_NONE || value16 > REVERB_PRESET_PLATE) {
return -EINVAL;
+ }
+ // REVERB_PRESET_NONE is mapped to bypass
+ if (value16 == REVERB_PRESET_NONE) {
+ pReverb->m_bBypass = 1;
+ } else {
+ pReverb->m_bBypass = 0;
+ pReverb->m_nNextRoom = value16 - 1;
+ }
+ } else {
+ switch (param) {
+ case REVERB_PARAM_ROOM_LEVEL:
+ case REVERB_PARAM_ROOM_HF_LEVEL:
+ case REVERB_PARAM_DECAY_HF_RATIO:
+ case REVERB_PARAM_REFLECTIONS_LEVEL:
+ case REVERB_PARAM_REVERB_LEVEL:
+ case REVERB_PARAM_DIFFUSION:
+ case REVERB_PARAM_DENSITY:
+ paramSize = sizeof(int16_t);
+ break;
- temp = Effects_MillibelsToLinear16(value16);
-
- pReverb->m_nRoomLpfFwd
- = MULT_EG1_EG1(temp, (32767 - pReverb->m_nRoomLpfFbk));
-
- LOGV("REVERB_PARAM_ROOM_LEVEL, gain %d, new m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
- if (param == REVERB_PARAM_ROOM_LEVEL)
+ case REVERB_PARAM_BYPASS:
+ case REVERB_PARAM_DECAY_TIME:
+ case REVERB_PARAM_REFLECTIONS_DELAY:
+ case REVERB_PARAM_REVERB_DELAY:
+ paramSize = sizeof(int32_t);
break;
- value16 = pProperties->roomHFLevel;
- /* FALL THROUGH */
- case REVERB_PARAM_ROOM_HF_LEVEL:
+ case REVERB_PARAM_PROPERTIES:
+ paramSize = sizeof(t_reverb_properties);
+ break;
- // Limit to 0 , -40dB range because of low pass implementation
- if (value16 > 0 || value16 < -4000)
+ default:
return -EINVAL;
- // Convert attenuation @ 5000H expressed in millibels to => m_nRoomLpfFbk
- // m_nRoomLpfFbk is -a1 where a1 is the solution of:
- // a1^2 + 2*(C-dG^2)/(1-dG^2)*a1 + 1 = 0 where:
- // - C is cos(2*pi*5000/Fs) (pReverb->m_nCosWT_5KHz)
- // - dG is G0/Gf (G0 is the linear gain at DC and Gf is the wanted gain at 5000Hz)
-
- // Save current DC gain m_nRoomLpfFwd / (32767 - m_nRoomLpfFbk) to keep it unchanged
- // while changing HF level
- temp2 = (pReverb->m_nRoomLpfFwd << 15) / (32767
- - pReverb->m_nRoomLpfFbk);
- if (value16 == 0) {
- pReverb->m_nRoomLpfFbk = 0;
- } else {
- int32_t dG2, b, delta;
-
- // dG^2
- temp = Effects_MillibelsToLinear16(value16);
- LOGV("REVERB_PARAM_ROOM_HF_LEVEL, HF gain %d", temp);
- temp = (1 << 30) / temp;
- LOGV("REVERB_PARAM_ROOM_HF_LEVEL, 1/ HF gain %d", temp);
- dG2 = (int32_t) (((int64_t) temp * (int64_t) temp) >> 15);
- LOGV("REVERB_PARAM_ROOM_HF_LEVEL, 1/ HF gain ^ 2 %d", dG2);
- // b = 2*(C-dG^2)/(1-dG^2)
- b = (int32_t) ((((int64_t) 1 << (15 + 1))
- * ((int64_t) pReverb->m_nCosWT_5KHz - (int64_t) dG2))
- / ((int64_t) 32767 - (int64_t) dG2));
-
- // delta = b^2 - 4
- delta = (int32_t) ((((int64_t) b * (int64_t) b) >> 15) - (1 << (15
- + 2)));
-
- LOGV_IF(delta > (1<<30), " delta overflow %d", delta);
-
- LOGV("REVERB_PARAM_ROOM_HF_LEVEL, dG2 %d, b %d, delta %d, m_nCosWT_5KHz %d", dG2, b, delta, pReverb->m_nCosWT_5KHz);
- // m_nRoomLpfFbk = -a1 = - (- b + sqrt(delta)) / 2
- pReverb->m_nRoomLpfFbk = (b - Effects_Sqrt(delta) * 181) >> 1;
}
- LOGV("REVERB_PARAM_ROOM_HF_LEVEL, olg DC gain %d new m_nRoomLpfFbk %d, old m_nRoomLpfFwd %d",
- temp2, pReverb->m_nRoomLpfFbk, pReverb->m_nRoomLpfFwd);
- pReverb->m_nRoomLpfFwd
- = MULT_EG1_EG1(temp2, (32767 - pReverb->m_nRoomLpfFbk));
- LOGV("REVERB_PARAM_ROOM_HF_LEVEL, new m_nRoomLpfFwd %d", pReverb->m_nRoomLpfFwd);
-
- if (param == REVERB_PARAM_ROOM_HF_LEVEL)
- break;
- value32 = pProperties->decayTime;
- /* FALL THROUGH */
-
- case REVERB_PARAM_DECAY_TIME:
-
- // Convert milliseconds to => m_nRvbLpfFwd (function of m_nRvbLpfFbk)
- // convert ms to samples
- value32 = (value32 * pReverb->m_nSamplingRate) / 1000;
-
- // calculate valid decay time range as a function of current reverb delay and
- // max feed back gain. Min value <=> -40dB in one pass, Max value <=> feedback gain = -1 dB
- // Calculate attenuation for each round in late reverb given a total attenuation of -6000 millibels.
- // g = -6000 d/DT , g gain in millibels, d reverb delay, DT decay time
- averageDelay = pReverb->m_nLateDelay - pReverb->m_nMaxExcursion;
- averageDelay += ((pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn)
- + (pReverb->m_sAp1.m_zApOut - pReverb->m_sAp1.m_zApIn)) >> 1;
-
- temp = (-6000 * averageDelay) / value32;
- LOGV("REVERB_PARAM_DECAY_TIME, delay smps %d, DT smps %d, gain mB %d",averageDelay, value32, temp);
- if (temp < -4000 || temp > -100)
+ if (size != paramSize) {
return -EINVAL;
+ }
- // calculate low pass gain by adding reverb input attenuation (pReverb->m_nLateGain) and substrating output
- // xfade and sum gain (max +9dB)
- temp -= Effects_Linear16ToMillibels(pReverb->m_nLateGain) + 900;
- temp = Effects_MillibelsToLinear16(temp);
-
- // DC gain (temp) = b0 / (1 + a1) = pReverb->m_nRvbLpfFwd / (32767 - pReverb->m_nRvbLpfFbk)
- pReverb->m_nRvbLpfFwd
- = MULT_EG1_EG1(temp, (32767 - pReverb->m_nRvbLpfFbk));
+ if (paramSize == sizeof(int16_t)) {
+ value16 = *(int16_t *) pValue;
+ } else if (paramSize == sizeof(int32_t)) {
+ value32 = *(int32_t *) pValue;
+ } else {
+ pProperties = (t_reverb_properties *) pValue;
+ }
- LOGV("REVERB_PARAM_DECAY_TIME, gain %d, new m_nRvbLpfFwd %d, old m_nRvbLpfFbk %d, reverb gain %d", temp, pReverb->m_nRvbLpfFwd, pReverb->m_nRvbLpfFbk, Effects_Linear16ToMillibels(pReverb->m_nLateGain));
+ pPreset = &pReverb->m_sPreset.m_sPreset[pReverb->m_nNextRoom];
- if (param == REVERB_PARAM_DECAY_TIME)
+ switch (param) {
+ case REVERB_PARAM_BYPASS:
+ pReverb->m_bBypass = (uint16_t)value32;
break;
- value16 = pProperties->decayHFRatio;
- /* FALL THROUGH */
- case REVERB_PARAM_DECAY_HF_RATIO:
+ case REVERB_PARAM_PROPERTIES:
+ value16 = pProperties->roomLevel;
+ /* FALL THROUGH */
- // We limit max value to 1000 because reverb filter is lowpass only
- if (value16 < 100 || value16 > 1000)
- return -EINVAL;
- // Convert per mille to => m_nLpfFwd, m_nLpfFbk
-
- // Save current DC gain m_nRoomLpfFwd / (32767 - m_nRoomLpfFbk) to keep it unchanged
- // while changing HF level
- temp2 = (pReverb->m_nRvbLpfFwd << 15) / (32767 - pReverb->m_nRvbLpfFbk);
+ case REVERB_PARAM_ROOM_LEVEL:
+ // Convert millibels to linear 16 bit signed => m_nRoomLpfFwd
+ if (value16 > 0)
+ return -EINVAL;
- if (value16 == 1000) {
- pReverb->m_nRvbLpfFbk = 0;
- } else {
- int32_t dG2, b, delta;
+ temp = Effects_MillibelsToLinear16(value16);
- temp = Effects_Linear16ToMillibels(temp2);
- // G_5000Hz = G_DC * (1000/REVERB_PARAM_DECAY_HF_RATIO) in millibels
+ pReverb->m_nRoomLpfFwd
+ = MULT_EG1_EG1(temp, (32767 - pReverb->m_nRoomLpfFbk));
+
+ LOGV("REVERB_PARAM_ROOM_LEVEL, gain %d, new m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
+ if (param == REVERB_PARAM_ROOM_LEVEL)
+ break;
+ value16 = pProperties->roomHFLevel;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_ROOM_HF_LEVEL:
+
+ // Limit to 0 , -40dB range because of low pass implementation
+ if (value16 > 0 || value16 < -4000)
+ return -EINVAL;
+ // Convert attenuation @ 5000H expressed in millibels to => m_nRoomLpfFbk
+ // m_nRoomLpfFbk is -a1 where a1 is the solution of:
+ // a1^2 + 2*(C-dG^2)/(1-dG^2)*a1 + 1 = 0 where:
+ // - C is cos(2*pi*5000/Fs) (pReverb->m_nCosWT_5KHz)
+ // - dG is G0/Gf (G0 is the linear gain at DC and Gf is the wanted gain at 5000Hz)
+
+ // Save current DC gain m_nRoomLpfFwd / (32767 - m_nRoomLpfFbk) to keep it unchanged
+ // while changing HF level
+ temp2 = (pReverb->m_nRoomLpfFwd << 15) / (32767
+ - pReverb->m_nRoomLpfFbk);
+ if (value16 == 0) {
+ pReverb->m_nRoomLpfFbk = 0;
+ } else {
+ int32_t dG2, b, delta;
+
+ // dG^2
+ temp = Effects_MillibelsToLinear16(value16);
+ LOGV("REVERB_PARAM_ROOM_HF_LEVEL, HF gain %d", temp);
+ temp = (1 << 30) / temp;
+ LOGV("REVERB_PARAM_ROOM_HF_LEVEL, 1/ HF gain %d", temp);
+ dG2 = (int32_t) (((int64_t) temp * (int64_t) temp) >> 15);
+ LOGV("REVERB_PARAM_ROOM_HF_LEVEL, 1/ HF gain ^ 2 %d", dG2);
+ // b = 2*(C-dG^2)/(1-dG^2)
+ b = (int32_t) ((((int64_t) 1 << (15 + 1))
+ * ((int64_t) pReverb->m_nCosWT_5KHz - (int64_t) dG2))
+ / ((int64_t) 32767 - (int64_t) dG2));
+
+ // delta = b^2 - 4
+ delta = (int32_t) ((((int64_t) b * (int64_t) b) >> 15) - (1 << (15
+ + 2)));
+
+ LOGV_IF(delta > (1<<30), " delta overflow %d", delta);
+
+ LOGV("REVERB_PARAM_ROOM_HF_LEVEL, dG2 %d, b %d, delta %d, m_nCosWT_5KHz %d", dG2, b, delta, pReverb->m_nCosWT_5KHz);
+ // m_nRoomLpfFbk = -a1 = - (- b + sqrt(delta)) / 2
+ pReverb->m_nRoomLpfFbk = (b - Effects_Sqrt(delta) * 181) >> 1;
+ }
+ LOGV("REVERB_PARAM_ROOM_HF_LEVEL, olg DC gain %d new m_nRoomLpfFbk %d, old m_nRoomLpfFwd %d",
+ temp2, pReverb->m_nRoomLpfFbk, pReverb->m_nRoomLpfFwd);
+
+ pReverb->m_nRoomLpfFwd
+ = MULT_EG1_EG1(temp2, (32767 - pReverb->m_nRoomLpfFbk));
+ LOGV("REVERB_PARAM_ROOM_HF_LEVEL, new m_nRoomLpfFwd %d", pReverb->m_nRoomLpfFwd);
+
+ if (param == REVERB_PARAM_ROOM_HF_LEVEL)
+ break;
+ value32 = pProperties->decayTime;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_DECAY_TIME:
+
+ // Convert milliseconds to => m_nRvbLpfFwd (function of m_nRvbLpfFbk)
+ // convert ms to samples
+ value32 = (value32 * pReverb->m_nSamplingRate) / 1000;
+
+ // calculate valid decay time range as a function of current reverb delay and
+ // max feed back gain. Min value <=> -40dB in one pass, Max value <=> feedback gain = -1 dB
+ // Calculate attenuation for each round in late reverb given a total attenuation of -6000 millibels.
+ // g = -6000 d/DT , g gain in millibels, d reverb delay, DT decay time
+ averageDelay = pReverb->m_nLateDelay - pReverb->m_nMaxExcursion;
+ averageDelay += ((pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn)
+ + (pReverb->m_sAp1.m_zApOut - pReverb->m_sAp1.m_zApIn)) >> 1;
+
+ temp = (-6000 * averageDelay) / value32;
+ LOGV("REVERB_PARAM_DECAY_TIME, delay smps %d, DT smps %d, gain mB %d",averageDelay, value32, temp);
+ if (temp < -4000 || temp > -100)
+ return -EINVAL;
+
+ // calculate low pass gain by adding reverb input attenuation (pReverb->m_nLateGain) and substrating output
+ // xfade and sum gain (max +9dB)
+ temp -= Effects_Linear16ToMillibels(pReverb->m_nLateGain) + 900;
+ temp = Effects_MillibelsToLinear16(temp);
- value32 = ((int32_t) 1000 << 15) / (int32_t) value16;
- LOGV("REVERB_PARAM_DECAY_HF_RATIO, DC gain %d, DC gain mB %d, 1000/R %d", temp2, temp, value32);
+ // DC gain (temp) = b0 / (1 + a1) = pReverb->m_nRvbLpfFwd / (32767 - pReverb->m_nRvbLpfFbk)
+ pReverb->m_nRvbLpfFwd
+ = MULT_EG1_EG1(temp, (32767 - pReverb->m_nRvbLpfFbk));
- temp = (int32_t) (((int64_t) temp * (int64_t) value32) >> 15);
+ LOGV("REVERB_PARAM_DECAY_TIME, gain %d, new m_nRvbLpfFwd %d, old m_nRvbLpfFbk %d, reverb gain %d", temp, pReverb->m_nRvbLpfFwd, pReverb->m_nRvbLpfFbk, Effects_Linear16ToMillibels(pReverb->m_nLateGain));
- if (temp < -4000) {
- LOGV("REVERB_PARAM_DECAY_HF_RATIO HF gain overflow %d mB", temp);
- temp = -4000;
- }
+ if (param == REVERB_PARAM_DECAY_TIME)
+ break;
+ value16 = pProperties->decayHFRatio;
+ /* FALL THROUGH */
- temp = Effects_MillibelsToLinear16(temp);
- LOGV("REVERB_PARAM_DECAY_HF_RATIO, HF gain %d", temp);
- // dG^2
- temp = (temp2 << 15) / temp;
- dG2 = (int32_t) (((int64_t) temp * (int64_t) temp) >> 15);
+ case REVERB_PARAM_DECAY_HF_RATIO:
- // b = 2*(C-dG^2)/(1-dG^2)
- b = (int32_t) ((((int64_t) 1 << (15 + 1))
- * ((int64_t) pReverb->m_nCosWT_5KHz - (int64_t) dG2))
- / ((int64_t) 32767 - (int64_t) dG2));
+ // We limit max value to 1000 because reverb filter is lowpass only
+ if (value16 < 100 || value16 > 1000)
+ return -EINVAL;
+ // Convert per mille to => m_nLpfFwd, m_nLpfFbk
- // delta = b^2 - 4
- delta = (int32_t) ((((int64_t) b * (int64_t) b) >> 15) - (1 << (15
- + 2)));
+ // Save current DC gain m_nRoomLpfFwd / (32767 - m_nRoomLpfFbk) to keep it unchanged
+ // while changing HF level
+ temp2 = (pReverb->m_nRvbLpfFwd << 15) / (32767 - pReverb->m_nRvbLpfFbk);
- // m_nRoomLpfFbk = -a1 = - (- b + sqrt(delta)) / 2
- pReverb->m_nRvbLpfFbk = (b - Effects_Sqrt(delta) * 181) >> 1;
+ if (value16 == 1000) {
+ pReverb->m_nRvbLpfFbk = 0;
+ } else {
+ int32_t dG2, b, delta;
- LOGV("REVERB_PARAM_DECAY_HF_RATIO, dG2 %d, b %d, delta %d", dG2, b, delta);
+ temp = Effects_Linear16ToMillibels(temp2);
+ // G_5000Hz = G_DC * (1000/REVERB_PARAM_DECAY_HF_RATIO) in millibels
- }
+ value32 = ((int32_t) 1000 << 15) / (int32_t) value16;
+ LOGV("REVERB_PARAM_DECAY_HF_RATIO, DC gain %d, DC gain mB %d, 1000/R %d", temp2, temp, value32);
- LOGV("REVERB_PARAM_DECAY_HF_RATIO, gain %d, m_nRvbLpfFbk %d, m_nRvbLpfFwd %d", temp2, pReverb->m_nRvbLpfFbk, pReverb->m_nRvbLpfFwd);
+ temp = (int32_t) (((int64_t) temp * (int64_t) value32) >> 15);
- pReverb->m_nRvbLpfFwd
- = MULT_EG1_EG1(temp2, (32767 - pReverb->m_nRvbLpfFbk));
+ if (temp < -4000) {
+ LOGV("REVERB_PARAM_DECAY_HF_RATIO HF gain overflow %d mB", temp);
+ temp = -4000;
+ }
- if (param == REVERB_PARAM_DECAY_HF_RATIO)
- break;
- value16 = pProperties->reflectionsLevel;
- /* FALL THROUGH */
+ temp = Effects_MillibelsToLinear16(temp);
+ LOGV("REVERB_PARAM_DECAY_HF_RATIO, HF gain %d", temp);
+ // dG^2
+ temp = (temp2 << 15) / temp;
+ dG2 = (int32_t) (((int64_t) temp * (int64_t) temp) >> 15);
- case REVERB_PARAM_REFLECTIONS_LEVEL:
- // We limit max value to 0 because gain is limited to 0dB
- if (value16 > 0 || value16 < -6000)
- return -EINVAL;
+ // b = 2*(C-dG^2)/(1-dG^2)
+ b = (int32_t) ((((int64_t) 1 << (15 + 1))
+ * ((int64_t) pReverb->m_nCosWT_5KHz - (int64_t) dG2))
+ / ((int64_t) 32767 - (int64_t) dG2));
- // Convert millibels to linear 16 bit signed and recompute m_sEarlyL.m_nGain[i] and m_sEarlyR.m_nGain[i].
- value16 = Effects_MillibelsToLinear16(value16);
- for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
- pReverb->m_sEarlyL.m_nGain[i]
- = MULT_EG1_EG1(pPreset->m_sEarlyL.m_nGain[i],value16);
- pReverb->m_sEarlyR.m_nGain[i]
- = MULT_EG1_EG1(pPreset->m_sEarlyR.m_nGain[i],value16);
- }
- pReverb->m_nEarlyGain = value16;
- LOGV("REVERB_PARAM_REFLECTIONS_LEVEL, m_nEarlyGain %d", pReverb->m_nEarlyGain);
+ // delta = b^2 - 4
+ delta = (int32_t) ((((int64_t) b * (int64_t) b) >> 15) - (1 << (15
+ + 2)));
- if (param == REVERB_PARAM_REFLECTIONS_LEVEL)
- break;
- value32 = pProperties->reflectionsDelay;
- /* FALL THROUGH */
-
- case REVERB_PARAM_REFLECTIONS_DELAY:
- // We limit max value MAX_EARLY_TIME
- // convert ms to time units
- temp = (value32 * 65536) / 1000;
- if (temp < 0 || temp > MAX_EARLY_TIME)
- return -EINVAL;
+ // m_nRoomLpfFbk = -a1 = - (- b + sqrt(delta)) / 2
+ pReverb->m_nRvbLpfFbk = (b - Effects_Sqrt(delta) * 181) >> 1;
- maxSamples = (int32_t) (MAX_EARLY_TIME * pReverb->m_nSamplingRate)
- >> 16;
- temp = (temp * pReverb->m_nSamplingRate) >> 16;
- for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
- temp2 = temp + (((int32_t) pPreset->m_sEarlyL.m_zDelay[i]
- * pReverb->m_nSamplingRate) >> 16);
- if (temp2 > maxSamples)
- temp2 = maxSamples;
- pReverb->m_sEarlyL.m_zDelay[i] = pReverb->m_nEarly0in + temp2;
- temp2 = temp + (((int32_t) pPreset->m_sEarlyR.m_zDelay[i]
- * pReverb->m_nSamplingRate) >> 16);
- if (temp2 > maxSamples)
- temp2 = maxSamples;
- pReverb->m_sEarlyR.m_zDelay[i] = pReverb->m_nEarly1in + temp2;
- }
- pReverb->m_nEarlyDelay = temp;
+ LOGV("REVERB_PARAM_DECAY_HF_RATIO, dG2 %d, b %d, delta %d", dG2, b, delta);
- LOGV("REVERB_PARAM_REFLECTIONS_DELAY, m_nEarlyDelay smps %d max smp delay %d", pReverb->m_nEarlyDelay, maxSamples);
+ }
- // Convert milliseconds to sample count => m_nEarlyDelay
- if (param == REVERB_PARAM_REFLECTIONS_DELAY)
- break;
- value16 = pProperties->reverbLevel;
- /* FALL THROUGH */
+ LOGV("REVERB_PARAM_DECAY_HF_RATIO, gain %d, m_nRvbLpfFbk %d, m_nRvbLpfFwd %d", temp2, pReverb->m_nRvbLpfFbk, pReverb->m_nRvbLpfFwd);
- case REVERB_PARAM_REVERB_LEVEL:
- // We limit max value to 0 because gain is limited to 0dB
- if (value16 > 0 || value16 < -6000)
- return -EINVAL;
- // Convert millibels to linear 16 bits (gange 0 - 8191) => m_nLateGain.
- pReverb->m_nLateGain = Effects_MillibelsToLinear16(value16) >> 2;
+ pReverb->m_nRvbLpfFwd
+ = MULT_EG1_EG1(temp2, (32767 - pReverb->m_nRvbLpfFbk));
- LOGV("REVERB_PARAM_REVERB_LEVEL, m_nLateGain %d", pReverb->m_nLateGain);
+ if (param == REVERB_PARAM_DECAY_HF_RATIO)
+ break;
+ value16 = pProperties->reflectionsLevel;
+ /* FALL THROUGH */
- if (param == REVERB_PARAM_REVERB_LEVEL)
- break;
- value32 = pProperties->reverbDelay;
- /* FALL THROUGH */
-
- case REVERB_PARAM_REVERB_DELAY:
- // We limit max value to MAX_DELAY_TIME
- // convert ms to time units
- temp = (value32 * 65536) / 1000;
- if (temp < 0 || temp > MAX_DELAY_TIME)
- return -EINVAL;
+ case REVERB_PARAM_REFLECTIONS_LEVEL:
+ // We limit max value to 0 because gain is limited to 0dB
+ if (value16 > 0 || value16 < -6000)
+ return -EINVAL;
- maxSamples = (int32_t) (MAX_DELAY_TIME * pReverb->m_nSamplingRate)
- >> 16;
- temp = (temp * pReverb->m_nSamplingRate) >> 16;
- if ((temp + pReverb->m_nMaxExcursion) > maxSamples) {
- temp = maxSamples - pReverb->m_nMaxExcursion;
- }
- if (temp < pReverb->m_nMaxExcursion) {
- temp = pReverb->m_nMaxExcursion;
- }
+ // Convert millibels to linear 16 bit signed and recompute m_sEarlyL.m_nGain[i] and m_sEarlyR.m_nGain[i].
+ value16 = Effects_MillibelsToLinear16(value16);
+ for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
+ pReverb->m_sEarlyL.m_nGain[i]
+ = MULT_EG1_EG1(pPreset->m_sEarlyL.m_nGain[i],value16);
+ pReverb->m_sEarlyR.m_nGain[i]
+ = MULT_EG1_EG1(pPreset->m_sEarlyR.m_nGain[i],value16);
+ }
+ pReverb->m_nEarlyGain = value16;
+ LOGV("REVERB_PARAM_REFLECTIONS_LEVEL, m_nEarlyGain %d", pReverb->m_nEarlyGain);
+
+ if (param == REVERB_PARAM_REFLECTIONS_LEVEL)
+ break;
+ value32 = pProperties->reflectionsDelay;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_REFLECTIONS_DELAY:
+ // We limit max value MAX_EARLY_TIME
+ // convert ms to time units
+ temp = (value32 * 65536) / 1000;
+ if (temp < 0 || temp > MAX_EARLY_TIME)
+ return -EINVAL;
+
+ maxSamples = (int32_t) (MAX_EARLY_TIME * pReverb->m_nSamplingRate)
+ >> 16;
+ temp = (temp * pReverb->m_nSamplingRate) >> 16;
+ for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
+ temp2 = temp + (((int32_t) pPreset->m_sEarlyL.m_zDelay[i]
+ * pReverb->m_nSamplingRate) >> 16);
+ if (temp2 > maxSamples)
+ temp2 = maxSamples;
+ pReverb->m_sEarlyL.m_zDelay[i] = pReverb->m_nEarly0in + temp2;
+ temp2 = temp + (((int32_t) pPreset->m_sEarlyR.m_zDelay[i]
+ * pReverb->m_nSamplingRate) >> 16);
+ if (temp2 > maxSamples)
+ temp2 = maxSamples;
+ pReverb->m_sEarlyR.m_zDelay[i] = pReverb->m_nEarly1in + temp2;
+ }
+ pReverb->m_nEarlyDelay = temp;
+
+ LOGV("REVERB_PARAM_REFLECTIONS_DELAY, m_nEarlyDelay smps %d max smp delay %d", pReverb->m_nEarlyDelay, maxSamples);
+
+ // Convert milliseconds to sample count => m_nEarlyDelay
+ if (param == REVERB_PARAM_REFLECTIONS_DELAY)
+ break;
+ value16 = pProperties->reverbLevel;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_REVERB_LEVEL:
+ // We limit max value to 0 because gain is limited to 0dB
+ if (value16 > 0 || value16 < -6000)
+ return -EINVAL;
+ // Convert millibels to linear 16 bits (gange 0 - 8191) => m_nLateGain.
+ pReverb->m_nLateGain = Effects_MillibelsToLinear16(value16) >> 2;
+
+ LOGV("REVERB_PARAM_REVERB_LEVEL, m_nLateGain %d", pReverb->m_nLateGain);
+
+ if (param == REVERB_PARAM_REVERB_LEVEL)
+ break;
+ value32 = pProperties->reverbDelay;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_REVERB_DELAY:
+ // We limit max value to MAX_DELAY_TIME
+ // convert ms to time units
+ temp = (value32 * 65536) / 1000;
+ if (temp < 0 || temp > MAX_DELAY_TIME)
+ return -EINVAL;
+
+ maxSamples = (int32_t) (MAX_DELAY_TIME * pReverb->m_nSamplingRate)
+ >> 16;
+ temp = (temp * pReverb->m_nSamplingRate) >> 16;
+ if ((temp + pReverb->m_nMaxExcursion) > maxSamples) {
+ temp = maxSamples - pReverb->m_nMaxExcursion;
+ }
+ if (temp < pReverb->m_nMaxExcursion) {
+ temp = pReverb->m_nMaxExcursion;
+ }
- temp -= pReverb->m_nLateDelay;
- pReverb->m_nDelay0Out += temp;
- pReverb->m_nDelay1Out += temp;
- pReverb->m_nLateDelay += temp;
+ temp -= pReverb->m_nLateDelay;
+ pReverb->m_nDelay0Out += temp;
+ pReverb->m_nDelay1Out += temp;
+ pReverb->m_nLateDelay += temp;
- LOGV("REVERB_PARAM_REVERB_DELAY, m_nLateDelay smps %d max smp delay %d", pReverb->m_nLateDelay, maxSamples);
+ LOGV("REVERB_PARAM_REVERB_DELAY, m_nLateDelay smps %d max smp delay %d", pReverb->m_nLateDelay, maxSamples);
- // Convert milliseconds to sample count => m_nDelay1Out + m_nMaxExcursion
- if (param == REVERB_PARAM_REVERB_DELAY)
- break;
+ // Convert milliseconds to sample count => m_nDelay1Out + m_nMaxExcursion
+ if (param == REVERB_PARAM_REVERB_DELAY)
+ break;
- value16 = pProperties->diffusion;
- /* FALL THROUGH */
+ value16 = pProperties->diffusion;
+ /* FALL THROUGH */
- case REVERB_PARAM_DIFFUSION:
- if (value16 < 0 || value16 > 1000)
- return -EINVAL;
+ case REVERB_PARAM_DIFFUSION:
+ if (value16 < 0 || value16 > 1000)
+ return -EINVAL;
- // Convert per mille to m_sAp0.m_nApGain, m_sAp1.m_nApGain
- pReverb->m_sAp0.m_nApGain = AP0_GAIN_BASE + ((int32_t) value16
- * AP0_GAIN_RANGE) / 1000;
- pReverb->m_sAp1.m_nApGain = AP1_GAIN_BASE + ((int32_t) value16
- * AP1_GAIN_RANGE) / 1000;
+ // Convert per mille to m_sAp0.m_nApGain, m_sAp1.m_nApGain
+ pReverb->m_sAp0.m_nApGain = AP0_GAIN_BASE + ((int32_t) value16
+ * AP0_GAIN_RANGE) / 1000;
+ pReverb->m_sAp1.m_nApGain = AP1_GAIN_BASE + ((int32_t) value16
+ * AP1_GAIN_RANGE) / 1000;
- LOGV("REVERB_PARAM_DIFFUSION, m_sAp0.m_nApGain %d m_sAp1.m_nApGain %d", pReverb->m_sAp0.m_nApGain, pReverb->m_sAp1.m_nApGain);
+ LOGV("REVERB_PARAM_DIFFUSION, m_sAp0.m_nApGain %d m_sAp1.m_nApGain %d", pReverb->m_sAp0.m_nApGain, pReverb->m_sAp1.m_nApGain);
- if (param == REVERB_PARAM_DIFFUSION)
- break;
+ if (param == REVERB_PARAM_DIFFUSION)
+ break;
- value16 = pProperties->density;
- /* FALL THROUGH */
+ value16 = pProperties->density;
+ /* FALL THROUGH */
- case REVERB_PARAM_DENSITY:
- if (value16 < 0 || value16 > 1000)
- return -EINVAL;
+ case REVERB_PARAM_DENSITY:
+ if (value16 < 0 || value16 > 1000)
+ return -EINVAL;
- // Convert per mille to m_sAp0.m_zApOut, m_sAp1.m_zApOut
- maxSamples = (int32_t) (MAX_AP_TIME * pReverb->m_nSamplingRate) >> 16;
+ // Convert per mille to m_sAp0.m_zApOut, m_sAp1.m_zApOut
+ maxSamples = (int32_t) (MAX_AP_TIME * pReverb->m_nSamplingRate) >> 16;
- temp = AP0_TIME_BASE + ((int32_t) value16 * AP0_TIME_RANGE) / 1000;
- /*lint -e{702} shift for performance */
- temp = (temp * pReverb->m_nSamplingRate) >> 16;
- if (temp > maxSamples)
- temp = maxSamples;
- pReverb->m_sAp0.m_zApOut = (uint16_t) (pReverb->m_sAp0.m_zApIn + temp);
+ temp = AP0_TIME_BASE + ((int32_t) value16 * AP0_TIME_RANGE) / 1000;
+ /*lint -e{702} shift for performance */
+ temp = (temp * pReverb->m_nSamplingRate) >> 16;
+ if (temp > maxSamples)
+ temp = maxSamples;
+ pReverb->m_sAp0.m_zApOut = (uint16_t) (pReverb->m_sAp0.m_zApIn + temp);
- LOGV("REVERB_PARAM_DENSITY, Ap0 delay smps %d", temp);
+ LOGV("REVERB_PARAM_DENSITY, Ap0 delay smps %d", temp);
- temp = AP1_TIME_BASE + ((int32_t) value16 * AP1_TIME_RANGE) / 1000;
- /*lint -e{702} shift for performance */
- temp = (temp * pReverb->m_nSamplingRate) >> 16;
- if (temp > maxSamples)
- temp = maxSamples;
- pReverb->m_sAp1.m_zApOut = (uint16_t) (pReverb->m_sAp1.m_zApIn + temp);
+ temp = AP1_TIME_BASE + ((int32_t) value16 * AP1_TIME_RANGE) / 1000;
+ /*lint -e{702} shift for performance */
+ temp = (temp * pReverb->m_nSamplingRate) >> 16;
+ if (temp > maxSamples)
+ temp = maxSamples;
+ pReverb->m_sAp1.m_zApOut = (uint16_t) (pReverb->m_sAp1.m_zApIn + temp);
- LOGV("Ap1 delay smps %d", temp);
+ LOGV("Ap1 delay smps %d", temp);
- break;
+ break;
- default:
- break;
+ default:
+ break;
+ }
}
+
return 0;
} /* end Reverb_setParameter */
@@ -1905,24 +1915,26 @@ static int ReverbUpdateRoom(reverb_object_t *pReverb, bool fullUpdate) {
*/
static int ReverbReadInPresets(reverb_object_t *pReverb) {
- int preset = 0;
- int defaultPreset = 0;
+ int preset;
- //now init any remaining presets to defaults
- for (defaultPreset = preset; defaultPreset < REVERB_MAX_ROOM_TYPE; defaultPreset++) {
- reverb_preset_t *pPreset = &pReverb->m_sPreset.m_sPreset[defaultPreset];
- if (defaultPreset == 0 || defaultPreset > REVERB_MAX_ROOM_TYPE - 1) {
- pPreset->m_nRvbLpfFbk = 8307;
- pPreset->m_nRvbLpfFwd = 14768;
+ // this is for test only. OpenSL ES presets are mapped to 4 presets.
+ // REVERB_PRESET_NONE is mapped to bypass
+ for (preset = 0; preset < REVERB_NUM_PRESETS; preset++) {
+ reverb_preset_t *pPreset = &pReverb->m_sPreset.m_sPreset[preset];
+ switch (preset + 1) {
+ case REVERB_PRESET_PLATE:
+ case REVERB_PRESET_SMALLROOM:
+ pPreset->m_nRvbLpfFbk = 5077;
+ pPreset->m_nRvbLpfFwd = 11076;
pPreset->m_nEarlyGain = 27690;
pPreset->m_nEarlyDelay = 1311;
pPreset->m_nLateGain = 8191;
pPreset->m_nLateDelay = 3932;
pPreset->m_nRoomLpfFbk = 3692;
- pPreset->m_nRoomLpfFwd = 24569;
+ pPreset->m_nRoomLpfFwd = 20474;
pPreset->m_sEarlyL.m_zDelay[0] = 1376;
pPreset->m_sEarlyL.m_nGain[0] = 22152;
- pPreset->m_sEarlyL.m_zDelay[1] = 2163;
+ pPreset->m_sEarlyL.m_zDelay[1] = 1462;
pPreset->m_sEarlyL.m_nGain[1] = 17537;
pPreset->m_sEarlyL.m_zDelay[2] = 0;
pPreset->m_sEarlyL.m_nGain[2] = 14768;
@@ -1941,11 +1953,11 @@ static int ReverbReadInPresets(reverb_object_t *pReverb) {
pPreset->m_sEarlyR.m_zDelay[4] = 0;
pPreset->m_sEarlyR.m_nGain[4] = 13384;
pPreset->m_nMaxExcursion = 127;
- pPreset->m_nXfadeInterval = 6388;
- pPreset->m_nAp0_ApGain = 15691;
- pPreset->m_nAp0_ApOut = 711;
- pPreset->m_nAp1_ApGain = 16317;
- pPreset->m_nAp1_ApOut = 1029;
+ pPreset->m_nXfadeInterval = 6470; //6483;
+ pPreset->m_nAp0_ApGain = 14768;
+ pPreset->m_nAp0_ApOut = 792;
+ pPreset->m_nAp1_ApGain = 14777;
+ pPreset->m_nAp1_ApOut = 1191;
pPreset->m_rfu4 = 0;
pPreset->m_rfu5 = 0;
pPreset->m_rfu6 = 0;
@@ -1953,15 +1965,17 @@ static int ReverbReadInPresets(reverb_object_t *pReverb) {
pPreset->m_rfu8 = 0;
pPreset->m_rfu9 = 0;
pPreset->m_rfu10 = 0;
- } else if (defaultPreset == 1) {
- pPreset->m_nRvbLpfFbk = 6461;
- pPreset->m_nRvbLpfFwd = 14307;
+ break;
+ case REVERB_PRESET_MEDIUMROOM:
+ case REVERB_PRESET_LARGEROOM:
+ pPreset->m_nRvbLpfFbk = 5077;
+ pPreset->m_nRvbLpfFwd = 12922;
pPreset->m_nEarlyGain = 27690;
pPreset->m_nEarlyDelay = 1311;
pPreset->m_nLateGain = 8191;
pPreset->m_nLateDelay = 3932;
pPreset->m_nRoomLpfFbk = 3692;
- pPreset->m_nRoomLpfFwd = 24569;
+ pPreset->m_nRoomLpfFwd = 21703;
pPreset->m_sEarlyL.m_zDelay[0] = 1376;
pPreset->m_sEarlyL.m_nGain[0] = 22152;
pPreset->m_sEarlyL.m_zDelay[1] = 1462;
@@ -1983,11 +1997,11 @@ static int ReverbReadInPresets(reverb_object_t *pReverb) {
pPreset->m_sEarlyR.m_zDelay[4] = 0;
pPreset->m_sEarlyR.m_nGain[4] = 13384;
pPreset->m_nMaxExcursion = 127;
- pPreset->m_nXfadeInterval = 6391;
- pPreset->m_nAp0_ApGain = 15230;
- pPreset->m_nAp0_ApOut = 708;
- pPreset->m_nAp1_ApGain = 15547;
- pPreset->m_nAp1_ApOut = 1023;
+ pPreset->m_nXfadeInterval = 6449;
+ pPreset->m_nAp0_ApGain = 15691;
+ pPreset->m_nAp0_ApOut = 774;
+ pPreset->m_nAp1_ApGain = 16317;
+ pPreset->m_nAp1_ApOut = 1155;
pPreset->m_rfu4 = 0;
pPreset->m_rfu5 = 0;
pPreset->m_rfu6 = 0;
@@ -1995,15 +2009,16 @@ static int ReverbReadInPresets(reverb_object_t *pReverb) {
pPreset->m_rfu8 = 0;
pPreset->m_rfu9 = 0;
pPreset->m_rfu10 = 0;
- } else if (defaultPreset == 2) {
- pPreset->m_nRvbLpfFbk = 5077;
- pPreset->m_nRvbLpfFwd = 12922;
+ break;
+ case REVERB_PRESET_MEDIUMHALL:
+ pPreset->m_nRvbLpfFbk = 6461;
+ pPreset->m_nRvbLpfFwd = 14307;
pPreset->m_nEarlyGain = 27690;
pPreset->m_nEarlyDelay = 1311;
pPreset->m_nLateGain = 8191;
pPreset->m_nLateDelay = 3932;
pPreset->m_nRoomLpfFbk = 3692;
- pPreset->m_nRoomLpfFwd = 21703;
+ pPreset->m_nRoomLpfFwd = 24569;
pPreset->m_sEarlyL.m_zDelay[0] = 1376;
pPreset->m_sEarlyL.m_nGain[0] = 22152;
pPreset->m_sEarlyL.m_zDelay[1] = 1462;
@@ -2025,11 +2040,11 @@ static int ReverbReadInPresets(reverb_object_t *pReverb) {
pPreset->m_sEarlyR.m_zDelay[4] = 0;
pPreset->m_sEarlyR.m_nGain[4] = 13384;
pPreset->m_nMaxExcursion = 127;
- pPreset->m_nXfadeInterval = 6449;
- pPreset->m_nAp0_ApGain = 15691;
- pPreset->m_nAp0_ApOut = 774;
- pPreset->m_nAp1_ApGain = 16317;
- pPreset->m_nAp1_ApOut = 1155;
+ pPreset->m_nXfadeInterval = 6391;
+ pPreset->m_nAp0_ApGain = 15230;
+ pPreset->m_nAp0_ApOut = 708;
+ pPreset->m_nAp1_ApGain = 15547;
+ pPreset->m_nAp1_ApOut = 1023;
pPreset->m_rfu4 = 0;
pPreset->m_rfu5 = 0;
pPreset->m_rfu6 = 0;
@@ -2037,18 +2052,19 @@ static int ReverbReadInPresets(reverb_object_t *pReverb) {
pPreset->m_rfu8 = 0;
pPreset->m_rfu9 = 0;
pPreset->m_rfu10 = 0;
- } else if (defaultPreset == 3) {
- pPreset->m_nRvbLpfFbk = 5077;
- pPreset->m_nRvbLpfFwd = 11076;
+ break;
+ case REVERB_PRESET_LARGEHALL:
+ pPreset->m_nRvbLpfFbk = 8307;
+ pPreset->m_nRvbLpfFwd = 14768;
pPreset->m_nEarlyGain = 27690;
pPreset->m_nEarlyDelay = 1311;
pPreset->m_nLateGain = 8191;
pPreset->m_nLateDelay = 3932;
pPreset->m_nRoomLpfFbk = 3692;
- pPreset->m_nRoomLpfFwd = 20474;
+ pPreset->m_nRoomLpfFwd = 24569;
pPreset->m_sEarlyL.m_zDelay[0] = 1376;
pPreset->m_sEarlyL.m_nGain[0] = 22152;
- pPreset->m_sEarlyL.m_zDelay[1] = 1462;
+ pPreset->m_sEarlyL.m_zDelay[1] = 2163;
pPreset->m_sEarlyL.m_nGain[1] = 17537;
pPreset->m_sEarlyL.m_zDelay[2] = 0;
pPreset->m_sEarlyL.m_nGain[2] = 14768;
@@ -2067,11 +2083,11 @@ static int ReverbReadInPresets(reverb_object_t *pReverb) {
pPreset->m_sEarlyR.m_zDelay[4] = 0;
pPreset->m_sEarlyR.m_nGain[4] = 13384;
pPreset->m_nMaxExcursion = 127;
- pPreset->m_nXfadeInterval = 6470; //6483;
- pPreset->m_nAp0_ApGain = 14768;
- pPreset->m_nAp0_ApOut = 792;
- pPreset->m_nAp1_ApGain = 14777;
- pPreset->m_nAp1_ApOut = 1191;
+ pPreset->m_nXfadeInterval = 6388;
+ pPreset->m_nAp0_ApGain = 15691;
+ pPreset->m_nAp0_ApOut = 711;
+ pPreset->m_nAp1_ApGain = 16317;
+ pPreset->m_nAp1_ApOut = 1029;
pPreset->m_rfu4 = 0;
pPreset->m_rfu5 = 0;
pPreset->m_rfu6 = 0;
@@ -2079,6 +2095,7 @@ static int ReverbReadInPresets(reverb_object_t *pReverb) {
pPreset->m_rfu8 = 0;
pPreset->m_rfu9 = 0;
pPreset->m_rfu10 = 0;
+ break;
}
}
diff --git a/media/libeffects/EffectReverb.h b/media/libeffects/EffectReverb.h
index f5aadfa..5af316d 100644
--- a/media/libeffects/EffectReverb.h
+++ b/media/libeffects/EffectReverb.h
@@ -17,7 +17,8 @@
#ifndef ANDROID_EFFECTREVERB_H_
#define ANDROID_EFFECTREVERB_H_
-#include <media/EffectReverbApi.h>
+#include <media/EffectEnvironmentalReverbApi.h>
+#include <media/EffectPresetReverbApi.h>
/*------------------------------------
@@ -43,7 +44,7 @@ if the buffer size is a power of two.
#define REVERB_BUFFER_SIZE_IN_SAMPLES_MAX 16384
-#define REVERB_MAX_ROOM_TYPE 4 // any room numbers larger than this are invalid
+#define REVERB_NUM_PRESETS REVERB_PRESET_PLATE // REVERB_PRESET_NONE is not included
#define REVERB_MAX_NUM_REFLECTIONS 5 // max num reflections per channel
@@ -171,7 +172,7 @@ typedef struct
typedef struct
{
- reverb_preset_t m_sPreset[REVERB_MAX_ROOM_TYPE]; //array of presets
+ reverb_preset_t m_sPreset[REVERB_NUM_PRESETS]; // array of presets(does not include REVERB_PRESET_NONE)
} reverb_preset_bank_t;
diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp
index 783249d..df0f73b 100644
--- a/media/libmedia/AudioEffect.cpp
+++ b/media/libmedia/AudioEffect.cpp
@@ -52,7 +52,7 @@ AudioEffect::AudioEffect(const effect_uuid_t *type,
)
: mStatus(NO_INIT)
{
- mStatus = set(type, uuid, priority, cbf, user, output, sessionId);
+ mStatus = set(type, uuid, priority, cbf, user, sessionId, output);
}
AudioEffect::AudioEffect(const char *typeStr,
@@ -84,7 +84,7 @@ AudioEffect::AudioEffect(const char *typeStr,
}
}
- mStatus = set(pType, pUuid, priority, cbf, user, output, sessionId);
+ mStatus = set(pType, pUuid, priority, cbf, user, sessionId, output);
}
status_t AudioEffect::set(const effect_uuid_t *type,
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 4872047..5401ec0 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -511,11 +511,17 @@ status_t MediaPlayerService::dump(int fd, const Vector<String16>& args)
sp<Client> c = mClients[i].promote();
if (c != 0) c->dump(fd, args);
}
- for (int i = 0, n = mMediaRecorderClients.size(); i < n; ++i) {
- result.append(" MediaRecorderClient\n");
- sp<MediaRecorderClient> c = mMediaRecorderClients[i].promote();
- snprintf(buffer, 255, " pid(%d)\n\n", c->mPid);
- result.append(buffer);
+ if (mMediaRecorderClients.size() == 0) {
+ result.append(" No media recorder client\n\n");
+ } else {
+ for (int i = 0, n = mMediaRecorderClients.size(); i < n; ++i) {
+ sp<MediaRecorderClient> c = mMediaRecorderClients[i].promote();
+ snprintf(buffer, 255, " MediaRecorderClient pid(%d)\n", c->mPid);
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ result = "\n";
+ c->dump(fd, args);
+ }
}
result.append(" Files opened and/or mapped:\n");
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 80b1cfd..fef3e6e 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -329,5 +329,12 @@ status_t MediaRecorderClient::setListener(const sp<IMediaRecorderClient>& listen
return mRecorder->setListener(listener);
}
+status_t MediaRecorderClient::dump(int fd, const Vector<String16>& args) const {
+ if (mRecorder != NULL) {
+ return mRecorder->dump(fd, args);
+ }
+ return OK;
+}
+
}; // namespace android
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index b53d950..d12e558 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -28,7 +28,7 @@ class MediaPlayerService;
class MediaRecorderClient : public BnMediaRecorder
{
public:
- virtual status_t setCamera(const sp<ICamera>& camera);
+ virtual status_t setCamera(const sp<ICamera>& camera);
virtual status_t setPreviewSurface(const sp<ISurface>& surface);
virtual status_t setVideoSource(int vs);
virtual status_t setAudioSource(int as);
@@ -45,21 +45,22 @@ public:
virtual status_t getMaxAmplitude(int* max);
virtual status_t start();
virtual status_t stop();
- virtual status_t reset();
+ virtual status_t reset();
virtual status_t init();
virtual status_t close();
virtual status_t release();
+ virtual status_t dump(int fd, const Vector<String16>& args) const;
private:
- friend class MediaPlayerService; // for accessing private constructor
+ friend class MediaPlayerService; // for accessing private constructor
- MediaRecorderClient(const sp<MediaPlayerService>& service, pid_t pid);
- virtual ~MediaRecorderClient();
+ MediaRecorderClient(const sp<MediaPlayerService>& service, pid_t pid);
+ virtual ~MediaRecorderClient();
- pid_t mPid;
- Mutex mLock;
- MediaRecorderBase *mRecorder;
- sp<MediaPlayerService> mMediaPlayerService;
+ pid_t mPid;
+ Mutex mLock;
+ MediaRecorderBase *mRecorder;
+ sp<MediaPlayerService> mMediaPlayerService;
};
}; // namespace android
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 50f74f2..72061ad 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -1057,4 +1057,64 @@ status_t StagefrightRecorder::getMaxAmplitude(int *max) {
return OK;
}
+status_t StagefrightRecorder::dump(int fd, const Vector<String16>& args) const {
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, SIZE, " Recorder: %p", this);
+ snprintf(buffer, SIZE, " Output file (fd %d):\n", mOutputFd);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " File format: %d\n", mOutputFormat);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Max file size (bytes): %lld\n", mMaxFileSizeBytes);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Max file duration (us): %lld\n", mMaxFileDurationUs);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " File offset length (bits): %d\n", mUse64BitFileOffset? 64: 32);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Interleave duration (us): %d\n", mInterleaveDurationUs);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Progress notification: %d frames\n", mTrackEveryNumberOfFrames);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Progress notification: %lld us\n", mTrackEveryTimeDurationUs);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Audio\n");
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Source: %d\n", mAudioSource);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Encoder: %d\n", mAudioEncoder);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Bit rate (bps): %d\n", mAudioBitRate);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Sampling rate (hz): %d\n", mSampleRate);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Number of channels: %d\n", mAudioChannels);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Max amplitude: %d\n", mAudioSourceNode == 0? 0: mAudioSourceNode->getMaxAmplitude());
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Video\n");
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Source: %d\n", mVideoSource);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Camera Id: %d\n", mCameraId);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Camera flags: %d\n", mFlags);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Encoder: %d\n", mVideoEncoder);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Encoder profile: %d\n", mVideoEncoderProfile);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Encoder level: %d\n", mVideoEncoderLevel);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " I frames interval (s): %d\n", mIFramesInterval);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Frame size (pixels): %dx%d\n", mVideoWidth, mVideoHeight);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Frame rate (fps): %d\n", mFrameRate);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Bit rate (bps): %d\n", mVideoBitRate);
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return OK;
+}
} // namespace android
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 85d2557..704523f 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -54,6 +54,7 @@ struct StagefrightRecorder : public MediaRecorderBase {
virtual status_t close();
virtual status_t reset();
virtual status_t getMaxAmplitude(int *max);
+ virtual status_t dump(int fd, const Vector<String16>& args) const;
private:
enum CameraFlags {
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 83f7040..efaab5b 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -948,7 +948,7 @@ status_t OMXCodec::getVideoProfileLevel(
int32_t supportedProfile = static_cast<int32_t>(param.eProfile);
int32_t supportedLevel = static_cast<int32_t>(param.eLevel);
- CODEC_LOGV("Supported profile: %ld, level %ld",
+ CODEC_LOGV("Supported profile: %d, level %d",
supportedProfile, supportedLevel);
if (profile == supportedProfile &&
diff --git a/media/libstagefright/codecs/aacdec/AACDecoder.cpp b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
index 2bc4448..f3b281f 100644
--- a/media/libstagefright/codecs/aacdec/AACDecoder.cpp
+++ b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
@@ -15,6 +15,7 @@
*/
#include "AACDecoder.h"
+#define LOG_TAG "AACDecoder"
#include "../../include/ESDS.h"
@@ -36,26 +37,33 @@ AACDecoder::AACDecoder(const sp<MediaSource> &source)
mAnchorTimeUs(0),
mNumSamplesOutput(0),
mInputBuffer(NULL) {
-}
-AACDecoder::~AACDecoder() {
- if (mStarted) {
- stop();
- }
+ sp<MetaData> srcFormat = mSource->getFormat();
- delete mConfig;
- mConfig = NULL;
-}
+ int32_t sampleRate;
+ CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
-status_t AACDecoder::start(MetaData *params) {
- CHECK(!mStarted);
+ mMeta = new MetaData;
+ mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
- mBufferGroup = new MediaBufferGroup;
- mBufferGroup->add_buffer(new MediaBuffer(2048 * 2));
+ // We'll always output stereo, regardless of how many channels are
+ // present in the input due to decoder limitations.
+ mMeta->setInt32(kKeyChannelCount, 2);
+ mMeta->setInt32(kKeySampleRate, sampleRate);
+
+ int64_t durationUs;
+ if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
+ mMeta->setInt64(kKeyDuration, durationUs);
+ }
+ mMeta->setCString(kKeyDecoderComponent, "AACDecoder");
+
+ mInitCheck = initCheck();
+}
+status_t AACDecoder::initCheck() {
+ memset(mConfig, 0, sizeof(tPVMP4AudioDecoderExternal));
mConfig->outputFormat = OUTPUTFORMAT_16PCM_INTERLEAVED;
- mConfig->aacPlusUpsamplingFactor = 0;
- mConfig->aacPlusEnabled = false;
+ mConfig->aacPlusEnabled = 1;
// The software decoder doesn't properly support mono output on
// AACplus files. Always output stereo.
@@ -64,8 +72,11 @@ status_t AACDecoder::start(MetaData *params) {
UInt32 memRequirements = PVMP4AudioDecoderGetMemRequirements();
mDecoderBuf = malloc(memRequirements);
- CHECK_EQ(PVMP4AudioDecoderInitLibrary(mConfig, mDecoderBuf),
- MP4AUDEC_SUCCESS);
+ status_t err = PVMP4AudioDecoderInitLibrary(mConfig, mDecoderBuf);
+ if (err != MP4AUDEC_SUCCESS) {
+ LOGE("Failed to initialize MP4 audio decoder");
+ return UNKNOWN_ERROR;
+ }
uint32_t type;
const void *data;
@@ -83,18 +94,38 @@ status_t AACDecoder::start(MetaData *params) {
mConfig->pInputBuffer = (UChar *)codec_specific_data;
mConfig->inputBufferCurrentLength = codec_specific_data_size;
mConfig->inputBufferMaxLength = 0;
- mConfig->inputBufferUsedLength = 0;
- mConfig->remainderBits = 0;
-
- mConfig->pOutputBuffer = NULL;
- mConfig->pOutputBuffer_plus = NULL;
- mConfig->repositionFlag = false;
if (PVMP4AudioDecoderConfig(mConfig, mDecoderBuf)
!= MP4AUDEC_SUCCESS) {
return ERROR_UNSUPPORTED;
}
+
+ // Check on the sampling rate to see whether it is changed.
+ int32_t sampleRate;
+ CHECK(mMeta->findInt32(kKeySampleRate, &sampleRate));
+ if (mConfig->samplingRate != sampleRate) {
+ mMeta->setInt32(kKeySampleRate, mConfig->samplingRate);
+ LOGW("Sample rate was %d, but now is %d",
+ sampleRate, mConfig->samplingRate);
+ }
}
+ return OK;
+}
+
+AACDecoder::~AACDecoder() {
+ if (mStarted) {
+ stop();
+ }
+
+ delete mConfig;
+ mConfig = NULL;
+}
+
+status_t AACDecoder::start(MetaData *params) {
+ CHECK(!mStarted);
+
+ mBufferGroup = new MediaBufferGroup;
+ mBufferGroup->add_buffer(new MediaBuffer(4096 * 2));
mSource->start();
@@ -127,28 +158,7 @@ status_t AACDecoder::stop() {
}
sp<MetaData> AACDecoder::getFormat() {
- sp<MetaData> srcFormat = mSource->getFormat();
-
- int32_t sampleRate;
- CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
-
- sp<MetaData> meta = new MetaData;
- meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
-
- // We'll always output stereo, regardless of how many channels are
- // present in the input due to decoder limitations.
- meta->setInt32(kKeyChannelCount, 2);
-
- meta->setInt32(kKeySampleRate, sampleRate);
-
- int64_t durationUs;
- if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
- meta->setInt64(kKeyDuration, durationUs);
- }
-
- meta->setCString(kKeyDecoderComponent, "AACDecoder");
-
- return meta;
+ return mMeta;
}
status_t AACDecoder::read(
@@ -200,13 +210,19 @@ status_t AACDecoder::read(
mConfig->remainderBits = 0;
mConfig->pOutputBuffer = static_cast<Int16 *>(buffer->data());
- mConfig->pOutputBuffer_plus = NULL;
+ mConfig->pOutputBuffer_plus = &mConfig->pOutputBuffer[2048];
mConfig->repositionFlag = false;
Int decoderErr = PVMP4AudioDecodeFrame(mConfig, mDecoderBuf);
size_t numOutBytes =
mConfig->frameLength * sizeof(int16_t) * mConfig->desiredChannels;
+ if (mConfig->aacPlusUpsamplingFactor == 2) {
+ if (mConfig->desiredChannels == 1) {
+ memcpy(&mConfig->pOutputBuffer[1024], &mConfig->pOutputBuffer[2048], numOutBytes * 2);
+ }
+ numOutBytes *= 2;
+ }
if (decoderErr != MP4AUDEC_SUCCESS) {
LOGW("AAC decoder returned error %d, substituting silence", decoderErr);
diff --git a/media/libstagefright/include/AACDecoder.h b/media/libstagefright/include/AACDecoder.h
index f09addd..200f93c 100644
--- a/media/libstagefright/include/AACDecoder.h
+++ b/media/libstagefright/include/AACDecoder.h
@@ -25,6 +25,7 @@ struct tPVMP4AudioDecoderExternal;
namespace android {
struct MediaBufferGroup;
+struct MetaData;
struct AACDecoder : public MediaSource {
AACDecoder(const sp<MediaSource> &source);
@@ -41,6 +42,7 @@ protected:
virtual ~AACDecoder();
private:
+ sp<MetaData> mMeta;
sp<MediaSource> mSource;
bool mStarted;
@@ -50,9 +52,11 @@ private:
void *mDecoderBuf;
int64_t mAnchorTimeUs;
int64_t mNumSamplesOutput;
+ status_t mInitCheck;
MediaBuffer *mInputBuffer;
+ status_t initCheck();
AACDecoder(const AACDecoder &);
AACDecoder &operator=(const AACDecoder &);
};
diff --git a/native/android/Android.mk b/native/android/Android.mk
index 376c64f..509a379 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -6,17 +6,18 @@ include $(CLEAR_VARS)
# our source files
#
LOCAL_SRC_FILES:= \
- activity.cpp \
input.cpp \
looper.cpp \
+ native_activity.cpp \
native_window.cpp
LOCAL_SHARED_LIBRARIES := \
- libandroid_runtime \
libcutils \
libutils \
libbinder \
- libui
+ libui \
+ libsurfaceflinger_client \
+ libandroid_runtime
LOCAL_C_INCLUDES += \
frameworks/base/native/include \
diff --git a/native/android/activity.cpp b/native/android/activity.cpp
deleted file mode 100644
index e69de29..0000000
--- a/native/android/activity.cpp
+++ /dev/null
diff --git a/native/android/input.cpp b/native/android/input.cpp
index 015a1ce..89d53e2 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -186,9 +186,9 @@ float AMotionEvent_getHistoricalSize(AInputEvent* motion_event, size_t pointer_i
}
void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
- ALooper_callbackFunc callback, void* data) {
+ ALooper_callbackFunc* callback, void* data) {
queue->setPollLoop(static_cast<android::PollLoop*>(looper));
- ALooper_setCallback(looper, queue->getConsumer().getChannel()->getReceivePipeFd(),
+ ALooper_addFd(looper, queue->getConsumer().getChannel()->getReceivePipeFd(),
POLLIN, callback, data);
}
diff --git a/native/android/looper.cpp b/native/android/looper.cpp
index 6e78bbd..1564c47 100644
--- a/native/android/looper.cpp
+++ b/native/android/looper.cpp
@@ -27,22 +27,41 @@ ALooper* ALooper_forThread() {
return PollLoop::getForThread().get();
}
-ALooper* ALooper_prepare() {
+ALooper* ALooper_prepare(int32_t opts) {
+ bool allowFds = (opts&ALOOPER_PREPARE_ALLOW_NON_CALLBACKS) != 0;
sp<PollLoop> loop = PollLoop::getForThread();
if (loop == NULL) {
- loop = new PollLoop();
+ loop = new PollLoop(allowFds);
PollLoop::setForThread(loop);
}
+ if (loop->getAllowNonCallbacks() != allowFds) {
+ LOGW("ALooper_prepare again with different ALOOPER_PREPARE_ALLOW_NON_CALLBACKS");
+ }
return loop.get();
}
-int32_t ALooper_pollOnce(int timeoutMillis) {
+int32_t ALooper_pollOnce(int timeoutMillis, int* outEvents, void** outData) {
sp<PollLoop> loop = PollLoop::getForThread();
if (loop == NULL) {
LOGW("ALooper_pollOnce: No looper for this thread!");
return -1;
}
- return loop->pollOnce(timeoutMillis) ? 1 : 0;
+ return loop->pollOnce(timeoutMillis, outEvents, outData);
+}
+
+int32_t ALooper_pollAll(int timeoutMillis, int* outEvents, void** outData) {
+ sp<PollLoop> loop = PollLoop::getForThread();
+ if (loop == NULL) {
+ LOGW("ALooper_pollOnce: No looper for this thread!");
+ return -1;
+ }
+
+ int32_t result;
+ while ((result = loop->pollOnce(timeoutMillis, outEvents, outData)) == ALOOPER_POLL_CALLBACK) {
+ ;
+ }
+
+ return result;
}
void ALooper_acquire(ALooper* looper) {
@@ -53,11 +72,11 @@ void ALooper_release(ALooper* looper) {
static_cast<PollLoop*>(looper)->decStrong((void*)ALooper_acquire);
}
-void ALooper_setCallback(ALooper* looper, int fd, int events,
+void ALooper_addFd(ALooper* looper, int fd, int events,
ALooper_callbackFunc* callback, void* data) {
static_cast<PollLoop*>(looper)->setLooperCallback(fd, events, callback, data);
}
-int32_t ALooper_removeCallback(ALooper* looper, int fd) {
+int32_t ALooper_removeFd(ALooper* looper, int fd) {
return static_cast<PollLoop*>(looper)->removeCallback(fd) ? 1 : 0;
}
diff --git a/native/android/native_activity.cpp b/native/android/native_activity.cpp
new file mode 100644
index 0000000..509cc33
--- /dev/null
+++ b/native/android/native_activity.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "native_activity"
+#include <utils/Log.h>
+
+#include <android_runtime/android_app_NativeActivity.h>
+
+using namespace android;
+
+void ANativeActivity_setWindowFormat(ANativeActivity* activity, int32_t format) {
+ android_NativeActivity_setWindowFormat(activity, format);
+}
+
+void ANativeActivity_setWindowFlags(ANativeActivity* activity,
+ uint32_t addFlags, uint32_t removeFlags) {
+ android_NativeActivity_setWindowFlags(activity, addFlags, addFlags|removeFlags);
+}
diff --git a/native/android/native_window.cpp b/native/android/native_window.cpp
index 448cbfc..bada078 100644
--- a/native/android/native_window.cpp
+++ b/native/android/native_window.cpp
@@ -17,10 +17,27 @@
#define LOG_TAG "Surface"
#include <utils/Log.h>
-#include <android/native_window.h>
+#include <android/native_window_jni.h>
#include <surfaceflinger/Surface.h>
+#include <android_runtime/android_view_Surface.h>
-using android::Surface;
+using namespace android;
+
+ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface) {
+ sp<ANativeWindow> win = android_Surface_getNativeWindow(env, surface);
+ if (win != NULL) {
+ win->incStrong((void*)ANativeWindow_acquire);
+ }
+ return win.get();
+}
+
+void ANativeWindow_acquire(ANativeWindow* window) {
+ window->incStrong((void*)ANativeWindow_acquire);
+}
+
+void ANativeWindow_release(ANativeWindow* window) {
+ window->decStrong((void*)ANativeWindow_acquire);
+}
static int32_t getWindowProp(ANativeWindow* window, int what) {
int value;
@@ -41,7 +58,40 @@ int32_t ANativeWindow_getFormat(ANativeWindow* window) {
}
int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width,
- int32_t height, int32_t format) {
- native_window_set_buffers_geometry(window, width, height, format);
+ int32_t height) {
+ native_window_set_buffers_geometry(window, width, height, 0);
return 0;
}
+
+int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
+ ARect* inOutDirtyBounds) {
+ Region dirtyRegion;
+ Region* dirtyParam = NULL;
+ if (inOutDirtyBounds != NULL) {
+ dirtyRegion.set(*(Rect*)inOutDirtyBounds);
+ dirtyParam = &dirtyRegion;
+ }
+
+ Surface::SurfaceInfo info;
+ status_t res = static_cast<Surface*>(window)->lock(&info, dirtyParam);
+ if (res != OK) {
+ return -1;
+ }
+
+ outBuffer->width = (int32_t)info.w;
+ outBuffer->height = (int32_t)info.h;
+ outBuffer->stride = (int32_t)info.s;
+ outBuffer->format = (int32_t)info.format;
+ outBuffer->bits = info.bits;
+
+ if (inOutDirtyBounds != NULL) {
+ *inOutDirtyBounds = dirtyRegion.getBounds();
+ }
+
+ return 0;
+}
+
+int32_t ANativeWindow_unlockAndPost(ANativeWindow* window) {
+ status_t res = static_cast<Surface*>(window)->unlockAndPost();
+ return res == android::OK ? 0 : -1;
+}
diff --git a/native/glue/threaded_app/Android.mk b/native/glue/threaded_app/Android.mk
new file mode 100644
index 0000000..cfc9b2a
--- /dev/null
+++ b/native/glue/threaded_app/Android.mk
@@ -0,0 +1,18 @@
+BASE_PATH := $(call my-dir)
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# our source files
+#
+LOCAL_SRC_FILES:= \
+ threaded_app.c
+
+LOCAL_C_INCLUDES += \
+ frameworks/base/native/include \
+ frameworks/base/core/jni/android \
+ dalvik/libnativehelper/include/nativehelper
+
+LOCAL_MODULE:= libthreaded_app
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/native/glue/threaded_app/threaded_app.c b/native/glue/threaded_app/threaded_app.c
new file mode 100644
index 0000000..2411e93
--- /dev/null
+++ b/native/glue/threaded_app/threaded_app.c
@@ -0,0 +1,279 @@
+/*
+ * 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.
+ *
+ */
+
+#include <jni.h>
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/resource.h>
+
+#include <android_glue/threaded_app.h>
+
+#include <android/log.h>
+
+#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "threaded_app", __VA_ARGS__))
+#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "threaded_app", __VA_ARGS__))
+
+int8_t android_app_read_cmd(struct android_app* android_app) {
+ int8_t cmd;
+ if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) {
+ return cmd;
+ } else {
+ LOGW("No data on command pipe!");
+ }
+ return -1;
+}
+
+int32_t android_app_exec_cmd(struct android_app* android_app, int8_t cmd) {
+ switch (cmd) {
+ case APP_CMD_INPUT_CHANGED:
+ LOGI("APP_CMD_INPUT_CHANGED\n");
+ pthread_mutex_lock(&android_app->mutex);
+ if (android_app->inputQueue != NULL) {
+ AInputQueue_detachLooper(android_app->inputQueue);
+ }
+ android_app->inputQueue = android_app->pendingInputQueue;
+ if (android_app->inputQueue != NULL) {
+ LOGI("Attaching input queue to looper");
+ AInputQueue_attachLooper(android_app->inputQueue,
+ android_app->looper, NULL, (void*)LOOPER_ID_EVENT);
+ }
+ pthread_cond_broadcast(&android_app->cond);
+ pthread_mutex_unlock(&android_app->mutex);
+ break;
+
+ case APP_CMD_WINDOW_CHANGED:
+ LOGI("APP_CMD_WINDOW_CHANGED\n");
+ pthread_mutex_lock(&android_app->mutex);
+ android_app->window = android_app->pendingWindow;
+ pthread_cond_broadcast(&android_app->cond);
+ pthread_mutex_unlock(&android_app->mutex);
+ break;
+
+ case APP_CMD_START:
+ case APP_CMD_RESUME:
+ case APP_CMD_PAUSE:
+ case APP_CMD_STOP:
+ LOGI("activityState=%d\n", cmd);
+ pthread_mutex_lock(&android_app->mutex);
+ android_app->activityState = cmd;
+ pthread_cond_broadcast(&android_app->cond);
+ pthread_mutex_unlock(&android_app->mutex);
+ break;
+
+ case APP_CMD_DESTROY:
+ LOGI("APP_CMD_DESTROY\n");
+ android_app->destroyRequested = 1;
+ break;
+ }
+
+ return android_app->destroyRequested ? 0 : 1;
+}
+
+static void android_app_destroy(struct android_app* android_app) {
+ LOGI("android_app_destroy!");
+ pthread_mutex_lock(&android_app->mutex);
+ if (android_app->inputQueue != NULL) {
+ AInputQueue_detachLooper(android_app->inputQueue);
+ }
+ android_app->destroyed = 1;
+ pthread_cond_broadcast(&android_app->cond);
+ pthread_mutex_unlock(&android_app->mutex);
+ // Can't touch android_app object after this.
+}
+
+static void* android_app_entry(void* param) {
+ struct android_app* android_app = (struct android_app*)param;
+
+ ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
+ ALooper_addFd(looper, android_app->msgread, POLLIN, NULL, (void*)LOOPER_ID_MAIN);
+ android_app->looper = looper;
+
+ pthread_mutex_lock(&android_app->mutex);
+ android_app->running = 1;
+ pthread_cond_broadcast(&android_app->cond);
+ pthread_mutex_unlock(&android_app->mutex);
+
+ android_main(android_app);
+
+ android_app_destroy(android_app);
+ return NULL;
+}
+
+// --------------------------------------------------------------------
+// Native activity interaction (called from main thread)
+// --------------------------------------------------------------------
+
+static struct android_app* android_app_create(ANativeActivity* activity) {
+ struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app));
+ memset(android_app, 0, sizeof(struct android_app));
+ android_app->activity = activity;
+
+ pthread_mutex_init(&android_app->mutex, NULL);
+ pthread_cond_init(&android_app->cond, NULL);
+
+ int msgpipe[2];
+ if (pipe(msgpipe)) {
+ LOGI("could not create pipe: %s", strerror(errno));
+ }
+ android_app->msgread = msgpipe[0];
+ android_app->msgwrite = msgpipe[1];
+
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ pthread_create(&android_app->thread, &attr, android_app_entry, android_app);
+
+ // Wait for thread to start.
+ pthread_mutex_lock(&android_app->mutex);
+ while (!android_app->running) {
+ pthread_cond_wait(&android_app->cond, &android_app->mutex);
+ }
+ pthread_mutex_unlock(&android_app->mutex);
+
+ return android_app;
+}
+
+static void android_app_write_cmd(struct android_app* android_app, int8_t cmd) {
+ if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) {
+ LOGI("Failure writing android_app cmd: %s\n", strerror(errno));
+ }
+}
+
+static void android_app_set_input(struct android_app* android_app, AInputQueue* inputQueue) {
+ pthread_mutex_lock(&android_app->mutex);
+ android_app->pendingInputQueue = inputQueue;
+ android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED);
+ while (android_app->inputQueue != android_app->pendingInputQueue) {
+ pthread_cond_wait(&android_app->cond, &android_app->mutex);
+ }
+ pthread_mutex_unlock(&android_app->mutex);
+}
+
+static void android_app_set_window(struct android_app* android_app, ANativeWindow* window) {
+ pthread_mutex_lock(&android_app->mutex);
+ android_app->pendingWindow = window;
+ android_app_write_cmd(android_app, APP_CMD_WINDOW_CHANGED);
+ while (android_app->window != android_app->pendingWindow) {
+ pthread_cond_wait(&android_app->cond, &android_app->mutex);
+ }
+ pthread_mutex_unlock(&android_app->mutex);
+}
+
+static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) {
+ pthread_mutex_lock(&android_app->mutex);
+ android_app_write_cmd(android_app, cmd);
+ while (android_app->activityState != cmd) {
+ pthread_cond_wait(&android_app->cond, &android_app->mutex);
+ }
+ pthread_mutex_unlock(&android_app->mutex);
+}
+
+static void android_app_free(struct android_app* android_app) {
+ pthread_mutex_lock(&android_app->mutex);
+ android_app_write_cmd(android_app, APP_CMD_DESTROY);
+ while (!android_app->destroyed) {
+ pthread_cond_wait(&android_app->cond, &android_app->mutex);
+ }
+ pthread_mutex_unlock(&android_app->mutex);
+
+ close(android_app->msgread);
+ close(android_app->msgwrite);
+ pthread_cond_destroy(&android_app->cond);
+ pthread_mutex_destroy(&android_app->mutex);
+ free(android_app);
+}
+
+static void onDestroy(ANativeActivity* activity) {
+ LOGI("Destroy: %p\n", activity);
+ android_app_free((struct android_app*)activity->instance);
+}
+
+static void onStart(ANativeActivity* activity) {
+ LOGI("Start: %p\n", activity);
+ android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START);
+}
+
+static void onResume(ANativeActivity* activity) {
+ LOGI("Resume: %p\n", activity);
+ android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME);
+}
+
+static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) {
+ LOGI("SaveInstanceState: %p\n", activity);
+ return NULL;
+}
+
+static void onPause(ANativeActivity* activity) {
+ LOGI("Pause: %p\n", activity);
+ android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE);
+}
+
+static void onStop(ANativeActivity* activity) {
+ LOGI("Stop: %p\n", activity);
+ android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP);
+}
+
+static void onLowMemory(ANativeActivity* activity) {
+ LOGI("LowMemory: %p\n", activity);
+}
+
+static void onWindowFocusChanged(ANativeActivity* activity, int focused) {
+ LOGI("WindowFocusChanged: %p -- %d\n", activity, focused);
+ android_app_write_cmd((struct android_app*)activity->instance,
+ focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS);
+}
+
+static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) {
+ LOGI("NativeWindowCreated: %p -- %p\n", activity, window);
+ android_app_set_window((struct android_app*)activity->instance, window);
+}
+
+static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) {
+ LOGI("NativeWindowDestroyed: %p -- %p\n", activity, window);
+ android_app_set_window((struct android_app*)activity->instance, NULL);
+}
+
+static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) {
+ LOGI("InputQueueCreated: %p -- %p\n", activity, queue);
+ android_app_set_input((struct android_app*)activity->instance, queue);
+}
+
+static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) {
+ LOGI("InputQueueDestroyed: %p -- %p\n", activity, queue);
+ android_app_set_input((struct android_app*)activity->instance, NULL);
+}
+
+void ANativeActivity_onCreate(ANativeActivity* activity,
+ void* savedState, size_t savedStateSize) {
+ LOGI("Creating: %p\n", activity);
+ activity->callbacks->onDestroy = onDestroy;
+ activity->callbacks->onStart = onStart;
+ activity->callbacks->onResume = onResume;
+ activity->callbacks->onSaveInstanceState = onSaveInstanceState;
+ activity->callbacks->onPause = onPause;
+ activity->callbacks->onStop = onStop;
+ activity->callbacks->onLowMemory = onLowMemory;
+ activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
+ activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
+ activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
+ activity->callbacks->onInputQueueCreated = onInputQueueCreated;
+ activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
+
+ activity->instance = android_app_create(activity);
+}
diff --git a/native/include/android/input.h b/native/include/android/input.h
index 75be85a..014b6a3 100644
--- a/native/include/android/input.h
+++ b/native/include/android/input.h
@@ -534,10 +534,11 @@ struct AInputQueue;
typedef struct AInputQueue AInputQueue;
/*
- * Add this input queue to a looper for processing.
+ * Add this input queue to a looper for processing. See
+ * ALooper_addFd() for information on the callback and data params.
*/
void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
- ALooper_callbackFunc callback, void* data);
+ ALooper_callbackFunc* callback, void* data);
/*
* Remove the input queue from the looper it is currently attached to.
diff --git a/native/include/android/looper.h b/native/include/android/looper.h
index 90a8983..2917216 100644
--- a/native/include/android/looper.h
+++ b/native/include/android/looper.h
@@ -24,25 +24,151 @@
extern "C" {
#endif
+/**
+ * ALooper
+ *
+ * A looper is the state tracking an event loop for a thread.
+ * Loopers do not define event structures or other such things; rather
+ * they are a lower-level facility to attach one or more discrete objects
+ * listening for an event. An "event" here is simply data available on
+ * a file descriptor: each attached object has an associated file descriptor,
+ * and waiting for "events" means (internally) polling on all of these file
+ * descriptors until one or more of them have data available.
+ *
+ * A thread can have only one ALooper associated with it.
+ */
struct ALooper;
typedef struct ALooper ALooper;
+/**
+ * For callback-based event loops, this is the prototype of the function
+ * that is called. It is given the file descriptor it is associated with,
+ * a bitmask of the poll events that were triggered (typically POLLIN), and
+ * the data pointer that was originally supplied.
+ *
+ * Implementations should return 1 to continue receiving callbacks, or 0
+ * to have this file descriptor and callback unregistered from the looper.
+ */
typedef int ALooper_callbackFunc(int fd, int events, void* data);
+/**
+ * Return the ALooper associated with the calling thread, or NULL if
+ * there is not one.
+ */
ALooper* ALooper_forThread();
-ALooper* ALooper_prepare();
+enum {
+ /**
+ * Option for ALooper_prepare: this ALooper will accept calls to
+ * ALooper_addFd() that do not have a callback (that is provide NULL
+ * for the callback). In this case the caller of ALooper_pollOnce()
+ * or ALooper_pollAll() MUST check the return from these functions to
+ * discover when data is available on such fds and process it.
+ */
+ ALOOPER_PREPARE_ALLOW_NON_CALLBACKS = 1<<0
+};
-int32_t ALooper_pollOnce(int timeoutMillis);
+/**
+ * Prepare an ALooper associated with the calling thread, and return it.
+ * If the thread already has an ALooper, it is returned. Otherwise, a new
+ * one is created, associated with the thread, and returned.
+ *
+ * The opts may be ALOOPER_PREPARE_ALLOW_NON_CALLBACKS or 0.
+ */
+ALooper* ALooper_prepare(int32_t opts);
+
+enum {
+ /**
+ * Result from ALooper_pollOnce() and ALooper_pollAll(): one or
+ * more callbacks were executed.
+ */
+ ALOOPER_POLL_CALLBACK = -1,
+
+ /**
+ * Result from ALooper_pollOnce() and ALooper_pollAll(): the
+ * timeout expired.
+ */
+ ALOOPER_POLL_TIMEOUT = -2,
+
+ /**
+ * Result from ALooper_pollOnce() and ALooper_pollAll(): an error
+ * occurred.
+ */
+ ALOOPER_POLL_ERROR = -3,
+};
+/**
+ * Wait for events to be available, with optional timeout in milliseconds.
+ * Invokes callbacks for all file descriptors on which an event occurred.
+ *
+ * If the timeout is zero, returns immediately without blocking.
+ * If the timeout is negative, waits indefinitely until an event appears.
+ *
+ * Returns ALOOPER_POLL_CALLBACK if a callback was invoked.
+ *
+ * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
+ * timeout expired.
+ *
+ * Returns ALOPER_POLL_ERROR if an error occurred.
+ *
+ * Returns a value >= 0 containing a file descriptor if it has data
+ * and it has no callback function (requiring the caller here to handle it).
+ * In this (and only this) case outEvents and outData will contain the poll
+ * events and data associated with the fd.
+ *
+ * This method does not return until it has finished invoking the appropriate callbacks
+ * for all file descriptors that were signalled.
+ */
+int32_t ALooper_pollOnce(int timeoutMillis, int* outEvents, void** outData);
+
+/**
+ * Like ALooper_pollOnce(), but performs all pending callbacks until all
+ * data has been consumed or a file descriptor is available with no callback.
+ * This function will never return ALOOPER_POLL_CALLBACK.
+ */
+int32_t ALooper_pollAll(int timeoutMillis, int* outEvents, void** outData);
+
+/**
+ * Acquire a reference on the given ALooper object. This prevents the object
+ * from being deleted until the reference is removed. This is only needed
+ * to safely hand an ALooper from one thread to another.
+ */
void ALooper_acquire(ALooper* looper);
+/**
+ * Remove a reference that was previously acquired with ALooper_acquire().
+ */
void ALooper_release(ALooper* looper);
-void ALooper_setCallback(ALooper* looper, int fd, int events,
+/**
+ * Add a new file descriptor to be polled by the looper. If the same file
+ * descriptor was previously added, it is replaced.
+ *
+ * "fd" is the file descriptor to be added.
+ * "events" are the poll events to wake up on. Typically this is POLLIN.
+ * "callback" is the function to call when there is an event on the file
+ * descriptor.
+ * "id" is an identifier to associated with this file descriptor, or 0.
+ * "data" is a private data pointer to supply to the callback.
+ *
+ * There are two main uses of this function:
+ *
+ * (1) If "callback" is non-NULL, then
+ * this function will be called when there is data on the file descriptor. It
+ * should execute any events it has pending, appropriately reading from the
+ * file descriptor.
+ *
+ * (2) If "callback" is NULL, the fd will be returned by ALooper_pollOnce
+ * when it has data available, requiring the caller to take care of processing
+ * it.
+ */
+void ALooper_addFd(ALooper* looper, int fd, int events,
ALooper_callbackFunc* callback, void* data);
-int32_t ALooper_removeCallback(ALooper* looper, int fd);
+/**
+ * Remove a previously added file descriptor from the looper.
+ */
+int32_t ALooper_removeFd(ALooper* looper, int fd);
#ifdef __cplusplus
};
diff --git a/native/include/android/native_activity.h b/native/include/android/native_activity.h
index a31c5af..d0ff052 100644
--- a/native/include/android/native_activity.h
+++ b/native/include/android/native_activity.h
@@ -192,6 +192,11 @@ typedef void ANativeActivity_createFunc(ANativeActivity* activity,
*/
extern ANativeActivity_createFunc ANativeActivity_onCreate;
+void ANativeActivity_setWindowFormat(ANativeActivity* activity, int32_t format);
+
+void ANativeActivity_setWindowFlags(ANativeActivity* activity,
+ uint32_t addFlags, uint32_t removeFlags);
+
#ifdef __cplusplus
};
#endif
diff --git a/native/include/android/native_window.h b/native/include/android/native_window.h
index 678ba3d..7599d7e 100644
--- a/native/include/android/native_window.h
+++ b/native/include/android/native_window.h
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-
#ifndef ANDROID_NATIVE_WINDOW_H
#define ANDROID_NATIVE_WINDOW_H
+#include <android/rect.h>
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -34,6 +35,27 @@ enum {
struct ANativeWindow;
typedef struct ANativeWindow ANativeWindow;
+typedef struct ANativeWindow_Buffer {
+ int32_t width;
+ int32_t height;
+ int32_t stride;
+ int32_t format;
+ void* bits;
+
+ uint32_t reserved[6];
+} ANativeWindow_Buffer;
+
+/**
+ * Acquire a reference on the given ANativeWindow object. This prevents the object
+ * from being deleted until the reference is removed.
+ */
+void ANativeWindow_acquire(ANativeWindow* window);
+
+/**
+ * Remove a reference that was previously acquired with ANativeWindow_acquire().
+ */
+void ANativeWindow_release(ANativeWindow* window);
+
/*
* Return the current width in pixels of the window surface. Returns a
* negative value on error.
@@ -60,13 +82,22 @@ int32_t ANativeWindow_getFormat(ANativeWindow* window);
* window's physical size, then it buffer will be scaled to match that size
* when compositing it to the screen.
*
- * The format may be one of the window format constants above.
- *
- * For all of these parameters, if 0 is supplied than the window's base
+ * For all of these parameters, if 0 is supplied then the window's base
* value will come back in force.
*/
-int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width,
- int32_t height, int32_t format);
+int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width, int32_t height);
+
+/**
+ * Lock the window's next drawing surface for writing.
+ */
+int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
+ ARect* inOutDirtyBounds);
+
+/**
+ * Unlock the window's drawing surface after previously locking it,
+ * posting the new buffer to the display.
+ */
+int32_t ANativeWindow_unlockAndPost(ANativeWindow* window);
#ifdef __cplusplus
};
diff --git a/native/include/android/native_window_jni.h b/native/include/android/native_window_jni.h
new file mode 100644
index 0000000..b9e72ef
--- /dev/null
+++ b/native/include/android/native_window_jni.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_NATIVE_WINDOW_JNI_H
+#define ANDROID_NATIVE_WINDOW_JNI_H
+
+#include <android/native_window.h>
+
+#include <jni.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Return the ANativeWindow associated with a Java Surface object,
+ * for interacting with it through native code. This acquires a reference
+ * on the ANativeWindow that is returned; be sure to use ANativeWindow_release()
+ * when done with it so that it doesn't leak.
+ */
+ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // ANDROID_NATIVE_WINDOW_H
diff --git a/native/include/android/rect.h b/native/include/android/rect.h
new file mode 100644
index 0000000..3e81f53
--- /dev/null
+++ b/native/include/android/rect.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef ANDROID_RECT_H
+#define ANDROID_RECT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ARect {
+ int32_t left;
+ int32_t top;
+ int32_t right;
+ int32_t bottom;
+} ARect;
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // ANDROID_RECT_H
diff --git a/native/include/android/window.h b/native/include/android/window.h
new file mode 100644
index 0000000..2ab192b
--- /dev/null
+++ b/native/include/android/window.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef ANDROID_WINDOW_H
+#define ANDROID_WINDOW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Window flags, as per the Java API at android.view.WindowManager.LayoutParams.
+ */
+enum {
+ AWINDOW_FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001,
+ AWINDOW_FLAG_DIM_BEHIND = 0x00000002,
+ AWINDOW_FLAG_BLUR_BEHIND = 0x00000004,
+ AWINDOW_FLAG_NOT_FOCUSABLE = 0x00000008,
+ AWINDOW_FLAG_NOT_TOUCHABLE = 0x00000010,
+ AWINDOW_FLAG_NOT_TOUCH_MODAL = 0x00000020,
+ AWINDOW_FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040,
+ AWINDOW_FLAG_KEEP_SCREEN_ON = 0x00000080,
+ AWINDOW_FLAG_LAYOUT_IN_SCREEN = 0x00000100,
+ AWINDOW_FLAG_LAYOUT_NO_LIMITS = 0x00000200,
+ AWINDOW_FLAG_FULLSCREEN = 0x00000400,
+ AWINDOW_FLAG_FORCE_NOT_FULLSCREEN = 0x00000800,
+ AWINDOW_FLAG_DITHER = 0x00001000,
+ AWINDOW_FLAG_SECURE = 0x00002000,
+ AWINDOW_FLAG_SCALED = 0x00004000,
+ AWINDOW_FLAG_IGNORE_CHEEK_PRESSES = 0x00008000,
+ AWINDOW_FLAG_LAYOUT_INSET_DECOR = 0x00010000,
+ AWINDOW_FLAG_ALT_FOCUSABLE_IM = 0x00020000,
+ AWINDOW_FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000,
+ AWINDOW_FLAG_SHOW_WHEN_LOCKED = 0x00080000,
+ AWINDOW_FLAG_SHOW_WALLPAPER = 0x00100000,
+ AWINDOW_FLAG_TURN_SCREEN_ON = 0x00200000,
+ AWINDOW_FLAG_DISMISS_KEYGUARD = 0x00400000,
+};
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // ANDROID_WINDOW_H
diff --git a/native/include/android_glue/threaded_app.h b/native/include/android_glue/threaded_app.h
new file mode 100644
index 0000000..adfdbea
--- /dev/null
+++ b/native/include/android_glue/threaded_app.h
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ *
+ */
+
+#include <poll.h>
+#include <pthread.h>
+#include <sched.h>
+
+#include <android/native_activity.h>
+#include <android/looper.h>
+
+/**
+ * This is the interface for the standard glue code of a threaded
+ * application. In this model, the application's code is running
+ * in its own thread separate from the main thread of the process.
+ * It is not required that this thread be associated with the Java
+ * VM, although it will need to be in order to make JNI calls any
+ * Java objects.
+ */
+struct android_app {
+ // The application can place a pointer to its own state object
+ // here if it likes.
+ void* userData;
+
+ // The ANativeActivity object instance that this app is running in.
+ ANativeActivity* activity;
+
+ // The ALooper associated with the app's thread.
+ ALooper* looper;
+
+ // When non-NULL, this is the input queue from which the app will
+ // receive user input events.
+ AInputQueue* inputQueue;
+
+ // When non-NULL, this is the window surface that the app can draw in.
+ ANativeWindow* window;
+
+ // Current state of the app's activity. May be either APP_CMD_START,
+ // APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below.
+ int activityState;
+
+ // -------------------------------------------------
+ // Below are "private" implementation of the glue code.
+
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+
+ int msgread;
+ int msgwrite;
+
+ pthread_t thread;
+
+ // This is non-zero when the application's NativeActivity is being
+ // destroyed and waiting for the app thread to complete.
+ int destroyRequested;
+
+ int running;
+ int destroyed;
+ AInputQueue* pendingInputQueue;
+ ANativeWindow* pendingWindow;
+};
+
+enum {
+ /**
+ * Looper data ID of commands coming from the app's main thread.
+ * These can be retrieved and processed with android_app_read_cmd()
+ * and android_app_exec_cmd().
+ */
+ LOOPER_ID_MAIN = 1,
+
+ /**
+ * Looper data ID of events coming from the AInputQueue of the
+ * application's window. These can be read via the inputQueue
+ * object of android_app.
+ */
+ LOOPER_ID_EVENT = 2
+};
+
+enum {
+ /**
+ * Command from main thread: the AInputQueue has changed. Upon processing
+ * this command, android_app->inputQueue will be updated to the new queue
+ * (or NULL).
+ */
+ APP_CMD_INPUT_CHANGED,
+
+ /**
+ * Command from main thread: the ANativeWindow has changed. Upon processing
+ * this command, android_app->window will be updated to the new window surface
+ * (or NULL).
+ */
+ APP_CMD_WINDOW_CHANGED,
+
+ /**
+ * Command from main thread: the app's activity window has gained
+ * input focus.
+ */
+ APP_CMD_GAINED_FOCUS,
+
+ /**
+ * Command from main thread: the app's activity window has lost
+ * input focus.
+ */
+ APP_CMD_LOST_FOCUS,
+
+ /**
+ * Command from main thread: the app's activity has been started.
+ */
+ APP_CMD_START,
+
+ /**
+ * Command from main thread: the app's activity has been resumed.
+ */
+ APP_CMD_RESUME,
+
+ /**
+ * Command from main thread: the app's activity has been paused.
+ */
+ APP_CMD_PAUSE,
+
+ /**
+ * Command from main thread: the app's activity has been stopped.
+ */
+ APP_CMD_STOP,
+
+ /**
+ * Command from main thread: the app's activity is being destroyed,
+ * and waiting for the app thread to clean up and exit before proceeding.
+ */
+ APP_CMD_DESTROY,
+};
+
+/**
+ * Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next
+ * app command message.
+ */
+int8_t android_app_read_cmd(struct android_app* android_app);
+
+/**
+ * Call with the command returned by android_app_read_cmd() to do the
+ * default processing of the given command.
+ *
+ * Important: returns 0 if the app should exit. You must ALWAYS check for
+ * a zero return and, if found, exit your android_main() function.
+ */
+int32_t android_app_exec_cmd(struct android_app* android_app, int8_t cmd);
+
+/**
+ * This is the function that application code must implement, representing
+ * the main entry to the app.
+ */
+extern void android_main(struct android_app* app);
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index f8abc5a..b9e915a4 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -244,27 +244,12 @@ public class StorageNotification extends StorageEventListener {
intent.setClass(mContext, com.android.systemui.usb.UsbStorageActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- final boolean adbOn = 1 == Settings.Secure.getInt(
- mContext.getContentResolver(),
- Settings.Secure.ADB_ENABLED,
- 0);
-
PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
setUsbStorageNotification(
com.android.internal.R.string.usb_storage_notification_title,
com.android.internal.R.string.usb_storage_notification_message,
com.android.internal.R.drawable.stat_sys_data_usb,
false, true, pi);
-
- if (POP_UMS_ACTIVITY_ON_CONNECT && !adbOn) {
- // We assume that developers don't want to enable UMS every
- // time they attach a device to a USB host. The average user,
- // however, is looking to charge the phone (in which case this
- // is harmless) or transfer files (in which case this coaches
- // the user about how to complete that task and saves several
- // steps).
- mContext.startActivity(intent);
- }
} else {
setUsbStorageNotification(0, 0, 0, false, false, null);
}
@@ -313,6 +298,23 @@ public class StorageNotification extends StorageEventListener {
}
mUsbStorageNotification.setLatestEventInfo(mContext, title, message, pi);
+ final boolean adbOn = 1 == Settings.Secure.getInt(
+ mContext.getContentResolver(),
+ Settings.Secure.ADB_ENABLED,
+ 0);
+
+ if (POP_UMS_ACTIVITY_ON_CONNECT && !adbOn) {
+ // Pop up a full-screen alert to coach the user through enabling UMS. The average
+ // user has attached the device to USB either to charge the phone (in which case
+ // this is harmless) or transfer files, and in the latter case this alert saves
+ // several steps (as well as subtly indicates that you shouldn't mix UMS with other
+ // activities on the device).
+ //
+ // If ADB is enabled, however, we suppress this dialog (under the assumption that a
+ // developer (a) knows how to enable UMS, and (b) is probably using USB to install
+ // builds or use adb commands.
+ mUsbStorageNotification.fullScreenIntent = pi;
+ }
}
final int notificationId = mUsbStorageNotification.icon;
diff --git a/test-runner/src/android/test/InstrumentationTestRunner.java b/test-runner/src/android/test/InstrumentationTestRunner.java
index 63d50c7..70d1643 100644
--- a/test-runner/src/android/test/InstrumentationTestRunner.java
+++ b/test-runner/src/android/test/InstrumentationTestRunner.java
@@ -496,9 +496,18 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu
return null;
}
+ /**
+ * Initialize the current thread as a looper.
+ * <p/>
+ * Exposed for unit testing.
+ */
+ void prepareLooper() {
+ Looper.prepare();
+ }
+
@Override
public void onStart() {
- Looper.prepare();
+ prepareLooper();
if (mJustCount) {
mResults.putString(Instrumentation.REPORT_KEY_IDENTIFIER, REPORT_VALUE_ID);
@@ -521,6 +530,11 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu
long runTime = System.currentTimeMillis() - startTime;
resultPrinter.print(mTestRunner.getTestResult(), runTime);
+ } catch (Throwable t) {
+ // catch all exceptions so a more verbose error message can be outputted
+ writer.println(String.format("Test run aborted due to unexpected exception: %s",
+ t.getMessage()));
+ t.printStackTrace(writer);
} finally {
mResults.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
String.format("\nTest results for %s=%s",
@@ -762,9 +776,11 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu
TimedTest.class).includeDetailedStats();
}
} catch (SecurityException e) {
- throw new IllegalStateException(e);
+ // ignore - the test with given name cannot be accessed. Will be handled during
+ // test execution
} catch (NoSuchMethodException e) {
- throw new IllegalStateException(e);
+ // ignore- the test with given name does not exist. Will be handled during test
+ // execution
}
if (mIsTimedTest && mIncludeDetailedStats) {
diff --git a/test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java b/test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java
index 6db72ad..d98b217 100644
--- a/test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java
+++ b/test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java
@@ -16,6 +16,7 @@
package android.test;
+import android.app.Instrumentation;
import android.content.Context;
import android.os.Bundle;
import android.test.mock.MockContext;
@@ -89,6 +90,42 @@ public class InstrumentationTestRunnerTest extends TestCase {
}
+ /**
+ * Test that runtime exceptions during runTest are handled gracefully
+ */
+ public void testUnhandledException() throws Exception {
+ StubAndroidTestRunner stubAndroidTestRunner = new StubAndroidTestRunner() {
+ @Override
+ public void runTest() {
+ throw new RuntimeException();
+ }
+ };
+ StubInstrumentationTestRunner instrumentationTestRunner = new StubInstrumentationTestRunner(
+ new StubContext("com.google.foo.tests"),
+ new StubContext(mTargetContextPackageName), stubAndroidTestRunner);
+ instrumentationTestRunner.onCreate(new Bundle());
+ instrumentationTestRunner.onStart();
+ assertTrue("Instrumentation did not finish", instrumentationTestRunner.isFinished());
+ // ensure a meaningful error message placed in results
+ String resultsData = instrumentationTestRunner.mResults.getString(
+ Instrumentation.REPORT_KEY_STREAMRESULT);
+ assertTrue("Instrumentation results is missing RuntimeException",
+ resultsData.contains("RuntimeException"));
+ }
+
+ /**
+ * Test that specifying a method which does not exist is handled gracefully
+ */
+ public void testBadMethodArgument() throws Exception {
+ String testClassName = PlaceHolderTest.class.getName();
+ String invalidMethodName = "testNoExist";
+ String classAndMethod = testClassName + "#" + invalidMethodName;
+ mInstrumentationTestRunner.onCreate(createBundle(
+ InstrumentationTestRunner.ARGUMENT_TEST_CLASS, classAndMethod));
+ assertTestRunnerCalledWithExpectedParameters(testClassName,
+ invalidMethodName);
+ }
+
public void testDelayParameter() throws Exception {
int delayMsec = 1000;
Bundle args = new Bundle();
@@ -170,6 +207,7 @@ public class InstrumentationTestRunnerTest extends TestCase {
private TestSuite mTestSuite;
private TestSuite mDefaultTestSuite;
private String mPackageNameForDefaultTests;
+ private Bundle mResults;
public StubInstrumentationTestRunner(Context context, Context targetContext,
AndroidTestRunner androidTestRunner) {
@@ -200,6 +238,7 @@ public class InstrumentationTestRunnerTest extends TestCase {
public void finish(int resultCode, Bundle results) {
mFinished = true;
+ mResults = results;
}
public boolean isStarted() {
@@ -221,6 +260,11 @@ public class InstrumentationTestRunnerTest extends TestCase {
public String getPackageNameForDefaultTests() {
return mPackageNameForDefaultTests;
}
+
+ @Override
+ void prepareLooper() {
+ // ignore
+ }
}
private static class StubContext extends MockContext {