diff options
| -rwxr-xr-x | media/java/android/media/audiofx/Visualizer.java | 81 | ||||
| -rw-r--r-- | media/jni/audioeffect/android_media_Visualizer.cpp | 22 | ||||
| -rw-r--r-- | media/libmedia/AudioEffect.cpp | 14 | ||||
| -rw-r--r-- | media/libmedia/IEffect.cpp | 11 | ||||
| -rw-r--r-- | media/libmedia/Visualizer.cpp | 2 |
5 files changed, 112 insertions, 18 deletions
diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java index 1f1e60d6436d..91d0addde5f8 100755 --- a/media/java/android/media/audiofx/Visualizer.java +++ b/media/java/android/media/audiofx/Visualizer.java @@ -84,6 +84,7 @@ public class Visualizer { // to keep in sync with frameworks/base/media/jni/audioeffect/android_media_Visualizer.cpp private static final int NATIVE_EVENT_PCM_CAPTURE = 0; private static final int NATIVE_EVENT_FFT_CAPTURE = 1; + private static final int NATIVE_EVENT_SERVER_DIED = 2; // Error codes: /** @@ -147,6 +148,10 @@ public class Visualizer { * PCM and FFT capture listener registered by client */ private OnDataCaptureListener mCaptureListener = null; + /** + * Server Died listener registered by client + */ + private OnServerDiedListener mServerDiedListener = null; // accessed by native methods private int mNativeVisualizer; @@ -458,6 +463,43 @@ public class Visualizer { } /** + * @hide + * + * The OnServerDiedListener interface defines a method called by the Visualizer to indicate that + * the connection to the native media server has been broken and that the Visualizer object will + * need to be released and re-created. + * The client application can implement this interface and register the listener with the + * {@link #setServerDiedListener(OnServerDiedListener)} method. + */ + public interface OnServerDiedListener { + /** + * @hide + * + * Method called when the native media server has died. + * <p>If the native media server encounters a fatal error and needs to restart, the binder + * connection from the {@link #Visualizer} to the media server will be broken. Data capture + * callbacks will stop happening, and client initiated calls to the {@link #Visualizer} + * instance will fail with the error code {@link #DEAD_OBJECT}. To restore functionality, + * clients should {@link #release()} their old visualizer and create a new instance. + */ + void onServerDied(); + } + + /** + * @hide + * + * Registers an OnServerDiedListener interface. + * <p>Call this method with a null listener to stop receiving server death notifications. + * @return {@link #SUCCESS} in case of success, + */ + public int setServerDiedListener(OnServerDiedListener listener) { + synchronized (mListenerLock) { + mServerDiedListener = listener; + } + return SUCCESS; + } + + /** * Helper class to handle the forwarding of native events to the appropriate listeners */ private class NativeEventHandler extends Handler @@ -469,11 +511,7 @@ public class Visualizer { mVisualizer = v; } - @Override - public void handleMessage(Message msg) { - if (mVisualizer == null) { - return; - } + private void handleCaptureMessage(Message msg) { OnDataCaptureListener l = null; synchronized (mListenerLock) { l = mVisualizer.mCaptureListener; @@ -482,6 +520,7 @@ public class Visualizer { if (l != null) { byte[] data = (byte[])msg.obj; int samplingRate = msg.arg1; + switch(msg.what) { case NATIVE_EVENT_PCM_CAPTURE: l.onWaveFormDataCapture(mVisualizer, data, samplingRate); @@ -490,11 +529,41 @@ public class Visualizer { l.onFftDataCapture(mVisualizer, data, samplingRate); break; default: - Log.e(TAG,"Unknown native event: "+msg.what); + Log.e(TAG,"Unknown native event in handleCaptureMessge: "+msg.what); break; } } } + + private void handleServerDiedMessage(Message msg) { + OnServerDiedListener l = null; + synchronized (mListenerLock) { + l = mVisualizer.mServerDiedListener; + } + + if (l != null) + l.onServerDied(); + } + + @Override + public void handleMessage(Message msg) { + if (mVisualizer == null) { + return; + } + + switch(msg.what) { + case NATIVE_EVENT_PCM_CAPTURE: + case NATIVE_EVENT_FFT_CAPTURE: + handleCaptureMessage(msg); + break; + case NATIVE_EVENT_SERVER_DIED: + handleServerDiedMessage(msg); + break; + default: + Log.e(TAG,"Unknown native event: "+msg.what); + break; + } + } } //--------------------------------------------------------- diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp index 433c459c32b2..f015afbaf209 100644 --- a/media/jni/audioeffect/android_media_Visualizer.cpp +++ b/media/jni/audioeffect/android_media_Visualizer.cpp @@ -39,6 +39,7 @@ using namespace android; #define NATIVE_EVENT_PCM_CAPTURE 0 #define NATIVE_EVENT_FFT_CAPTURE 1 +#define NATIVE_EVENT_SERVER_DIED 2 // ---------------------------------------------------------------------------- static const char* const kClassPathName = "android/media/audiofx/Visualizer"; @@ -284,6 +285,23 @@ android_media_visualizer_native_init(JNIEnv *env) } +static void android_media_visualizer_effect_callback(int32_t event, + void *user, + void *info) { + if ((event == AudioEffect::EVENT_ERROR) && + (*((status_t*)info) == DEAD_OBJECT)) { + visualizerJniStorage* lpJniStorage = (visualizerJniStorage*)user; + visualizer_callback_cookie* callbackInfo = &lpJniStorage->mCallbackData; + JNIEnv *env = AndroidRuntime::getJNIEnv(); + + env->CallStaticVoidMethod( + callbackInfo->visualizer_class, + fields.midPostNativeEvent, + callbackInfo->visualizer_ref, + NATIVE_EVENT_SERVER_DIED, + 0, 0, 0); + } +} static jint android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, @@ -319,8 +337,8 @@ android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_th // create the native Visualizer object lpVisualizer = new Visualizer(0, - NULL, - NULL, + android_media_visualizer_effect_callback, + lpJniStorage, sessionId); if (lpVisualizer == NULL) { ALOGE("Error creating Visualizer"); diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp index f9f997fe6a32..19b7e324b32b 100644 --- a/media/libmedia/AudioEffect.cpp +++ b/media/libmedia/AudioEffect.cpp @@ -202,7 +202,7 @@ bool AudioEffect::getEnabled() const status_t AudioEffect::setEnabled(bool enabled) { if (mStatus != NO_ERROR) { - return INVALID_OPERATION; + return (mStatus == ALREADY_EXISTS) ? INVALID_OPERATION : mStatus; } status_t status = NO_ERROR; @@ -231,7 +231,7 @@ status_t AudioEffect::command(uint32_t cmdCode, { if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) { ALOGV("command() bad status %d", mStatus); - return INVALID_OPERATION; + return mStatus; } if (cmdCode == EFFECT_CMD_ENABLE || cmdCode == EFFECT_CMD_DISABLE) { @@ -263,7 +263,7 @@ status_t AudioEffect::command(uint32_t cmdCode, status_t AudioEffect::setParameter(effect_param_t *param) { if (mStatus != NO_ERROR) { - return INVALID_OPERATION; + return (mStatus == ALREADY_EXISTS) ? INVALID_OPERATION : mStatus; } if (param == NULL || param->psize == 0 || param->vsize == 0) { @@ -281,7 +281,7 @@ status_t AudioEffect::setParameter(effect_param_t *param) status_t AudioEffect::setParameterDeferred(effect_param_t *param) { if (mStatus != NO_ERROR) { - return INVALID_OPERATION; + return (mStatus == ALREADY_EXISTS) ? INVALID_OPERATION : mStatus; } if (param == NULL || param->psize == 0 || param->vsize == 0) { @@ -307,7 +307,7 @@ status_t AudioEffect::setParameterDeferred(effect_param_t *param) status_t AudioEffect::setParameterCommit() { if (mStatus != NO_ERROR) { - return INVALID_OPERATION; + return (mStatus == ALREADY_EXISTS) ? INVALID_OPERATION : mStatus; } Mutex::Autolock _l(mCblk->lock); @@ -321,7 +321,7 @@ status_t AudioEffect::setParameterCommit() status_t AudioEffect::getParameter(effect_param_t *param) { if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) { - return INVALID_OPERATION; + return mStatus; } if (param == NULL || param->psize == 0 || param->vsize == 0) { @@ -341,7 +341,7 @@ status_t AudioEffect::getParameter(effect_param_t *param) void AudioEffect::binderDied() { ALOGW("IEffect died"); - mStatus = NO_INIT; + mStatus = DEAD_OBJECT; if (mCbf != NULL) { status_t status = DEAD_OBJECT; mCbf(EVENT_ERROR, mUserData, &status); diff --git a/media/libmedia/IEffect.cpp b/media/libmedia/IEffect.cpp index d469e280f647..5d40cc82af48 100644 --- a/media/libmedia/IEffect.cpp +++ b/media/libmedia/IEffect.cpp @@ -83,8 +83,15 @@ public: size = *pReplySize; } data.writeInt32(size); - remote()->transact(COMMAND, data, &reply); - status_t status = reply.readInt32(); + + status_t status = remote()->transact(COMMAND, data, &reply); + if (status != NO_ERROR) { + if (pReplySize != NULL) + *pReplySize = 0; + return status; + } + + status = reply.readInt32(); size = reply.readInt32(); if (size != 0 && pReplyData != NULL && pReplySize != NULL) { reply.read(pReplyData, size); diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp index 13b64e9f2917..70f8c0c28e8e 100644 --- a/media/libmedia/Visualizer.cpp +++ b/media/libmedia/Visualizer.cpp @@ -168,7 +168,7 @@ status_t Visualizer::getWaveForm(uint8_t *waveform) uint32_t replySize = mCaptureSize; status = command(VISUALIZER_CMD_CAPTURE, 0, NULL, &replySize, waveform); ALOGV("getWaveForm() command returned %d", status); - if (replySize == 0) { + if ((status == NO_ERROR) && (replySize == 0)) { status = NOT_ENOUGH_DATA; } } else { |