summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/jni/android_media_AudioSystem.cpp54
-rw-r--r--media/java/android/media/AudioPortEventHandler.java14
2 files changed, 53 insertions, 15 deletions
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 4a98f27..fc05a6d 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -142,7 +142,14 @@ static struct {
static const char* const kEventHandlerClassPathName =
"android/media/AudioPortEventHandler";
-static jmethodID gPostEventFromNative;
+static struct {
+ jfieldID mJniCallback;
+} gEventHandlerFields;
+static struct {
+ jmethodID postEventFromNative;
+} gAudioPortEventHandlerMethods;
+
+static Mutex gLock;
enum AudioError {
kAudioStatusOk = 0,
@@ -173,14 +180,14 @@ public:
private:
void sendEvent(int event);
- jclass mClass; // Reference to AudioPortEventHandlerDelegate class
- jobject mObject; // Weak ref to AudioPortEventHandlerDelegate Java object to call on
+ jclass mClass; // Reference to AudioPortEventHandler class
+ jobject mObject; // Weak ref to AudioPortEventHandler Java object to call on
};
JNIAudioPortCallback::JNIAudioPortCallback(JNIEnv* env, jobject thiz, jobject weak_thiz)
{
- // Hold onto the SoundTriggerModule class for use in calling the static method
+ // Hold onto the AudioPortEventHandler class for use in calling the static method
// that posts events to the application thread.
jclass clazz = env->GetObjectClass(thiz);
if (clazz == NULL) {
@@ -189,7 +196,7 @@ JNIAudioPortCallback::JNIAudioPortCallback(JNIEnv* env, jobject thiz, jobject we
}
mClass = (jclass)env->NewGlobalRef(clazz);
- // We use a weak reference so the SoundTriggerModule object can be garbage collected.
+ // We use a weak reference so the AudioPortEventHandler object can be garbage collected.
// The reference is only used as a proxy for callbacks.
mObject = env->NewGlobalRef(weak_thiz);
}
@@ -211,7 +218,7 @@ void JNIAudioPortCallback::sendEvent(int event)
if (env == NULL) {
return;
}
- env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject,
+ env->CallStaticVoidMethod(mClass, gAudioPortEventHandlerMethods.postEventFromNative, mObject,
event, 0, 0, NULL);
if (env->ExceptionCheck()) {
ALOGW("An exception occurred while notifying an event.");
@@ -234,6 +241,23 @@ void JNIAudioPortCallback::onServiceDied()
sendEvent(AUDIOPORT_EVENT_SERVICE_DIED);
}
+static sp<JNIAudioPortCallback> setJniCallback(JNIEnv* env,
+ jobject thiz,
+ const sp<JNIAudioPortCallback>& callback)
+{
+ Mutex::Autolock l(gLock);
+ sp<JNIAudioPortCallback> old =
+ (JNIAudioPortCallback*)env->GetLongField(thiz, gEventHandlerFields.mJniCallback);
+ if (callback.get()) {
+ callback->incStrong((void*)setJniCallback);
+ }
+ if (old != 0) {
+ old->decStrong((void*)setJniCallback);
+ }
+ env->SetLongField(thiz, gEventHandlerFields.mJniCallback, (jlong)callback.get());
+ return old;
+}
+
static int check_AudioSystem_Command(status_t status)
{
switch (status) {
@@ -1355,7 +1379,9 @@ android_media_AudioSystem_eventHandlerSetup(JNIEnv *env, jobject thiz, jobject w
sp<JNIAudioPortCallback> callback = new JNIAudioPortCallback(env, thiz, weak_this);
- AudioSystem::setAudioPortCallback(callback);
+ if (AudioSystem::addAudioPortCallback(callback) == NO_ERROR) {
+ setJniCallback(env, thiz, callback);
+ }
}
static void
@@ -1363,9 +1389,11 @@ android_media_AudioSystem_eventHandlerFinalize(JNIEnv *env, jobject thiz)
{
ALOGV("eventHandlerFinalize");
- sp<JNIAudioPortCallback> callback;
+ sp<JNIAudioPortCallback> callback = setJniCallback(env, thiz, 0);
- AudioSystem::setAudioPortCallback(callback);
+ if (callback != 0) {
+ AudioSystem::removeAudioPortCallback(callback);
+ }
}
static jint
@@ -1636,9 +1664,11 @@ int register_android_media_AudioSystem(JNIEnv *env)
"Landroid/media/AudioHandle;");
jclass eventHandlerClass = FindClassOrDie(env, kEventHandlerClassPathName);
- gPostEventFromNative = GetStaticMethodIDOrDie(env, eventHandlerClass, "postEventFromNative",
- "(Ljava/lang/Object;IIILjava/lang/Object;)V");
-
+ gAudioPortEventHandlerMethods.postEventFromNative = GetStaticMethodIDOrDie(
+ env, eventHandlerClass, "postEventFromNative",
+ "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+ gEventHandlerFields.mJniCallback = GetFieldIDOrDie(env,
+ eventHandlerClass, "mJniCallback", "J");
jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix");
gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass);
diff --git a/media/java/android/media/AudioPortEventHandler.java b/media/java/android/media/AudioPortEventHandler.java
index c05fd77..c49e8c2 100644
--- a/media/java/android/media/AudioPortEventHandler.java
+++ b/media/java/android/media/AudioPortEventHandler.java
@@ -40,6 +40,12 @@ class AudioPortEventHandler {
private static final int AUDIOPORT_EVENT_SERVICE_DIED = 3;
private static final int AUDIOPORT_EVENT_NEW_LISTENER = 4;
+ /**
+ * Accessed by native methods: JNI Callback context.
+ */
+ @SuppressWarnings("unused")
+ private long mJniCallback;
+
void init() {
synchronized (this) {
if (mHandler != null) {
@@ -63,9 +69,6 @@ class AudioPortEventHandler {
listeners = mListeners;
}
}
- if (listeners.isEmpty()) {
- return;
- }
// reset audio port cache if the event corresponds to a change coming
// from audio policy service or if mediaserver process died.
if (msg.what == AUDIOPORT_EVENT_PORT_LIST_UPDATED ||
@@ -73,6 +76,11 @@ class AudioPortEventHandler {
msg.what == AUDIOPORT_EVENT_SERVICE_DIED) {
AudioManager.resetAudioPortGeneration();
}
+
+ if (listeners.isEmpty()) {
+ return;
+ }
+
ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
ArrayList<AudioPatch> patches = new ArrayList<AudioPatch>();
if (msg.what != AUDIOPORT_EVENT_SERVICE_DIED) {