diff options
-rw-r--r-- | core/jni/android_media_AudioSystem.cpp | 54 | ||||
-rw-r--r-- | media/java/android/media/AudioPortEventHandler.java | 14 |
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) { |