summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/java/android/media/AudioRecord.java3
-rw-r--r--media/java/android/media/AudioTrack.java3
-rw-r--r--media/java/android/media/ExifInterface.java10
-rw-r--r--media/java/android/media/MediaCodec.java47
-rw-r--r--media/java/android/media/midi/package.html63
-rw-r--r--media/jni/android_media_MediaCodec.cpp58
-rw-r--r--media/jni/android_media_MediaCodec.h7
-rw-r--r--media/jni/audioeffect/android_media_AudioEffect.cpp115
-rw-r--r--media/jni/audioeffect/android_media_Visualizer.cpp148
9 files changed, 270 insertions, 184 deletions
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 7eb1357..3cbc405 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -1277,7 +1277,8 @@ public class AudioRecord
native_enableDeviceCallback();
}
mRoutingChangeListeners.put(
- listener, new NativeRoutingEventHandlerDelegate(this, listener, handler));
+ listener, new NativeRoutingEventHandlerDelegate(this, listener,
+ handler != null ? handler : new Handler(mInitializationLooper)));
}
}
}
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 7293c6c..f395cb3 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -2244,7 +2244,8 @@ public class AudioTrack
native_enableDeviceCallback();
}
mRoutingChangeListeners.put(
- listener, new NativeRoutingEventHandlerDelegate(this, listener, handler));
+ listener, new NativeRoutingEventHandlerDelegate(this, listener,
+ handler != null ? handler : new Handler(mInitializationLooper)));
}
}
}
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index aa5d43a..6bf5721 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -57,6 +57,16 @@ public class ExifInterface {
public static final String TAG_APERTURE = "FNumber";
/** Type is String. */
public static final String TAG_ISO = "ISOSpeedRatings";
+ /** Type is String. */
+ public static final String TAG_DATETIME_DIGITIZED = "DateTimeDigitized";
+ /** Type is int. */
+ public static final String TAG_SUBSEC_TIME = "SubSecTime";
+ /** Type is int. */
+ public static final String TAG_SUBSEC_TIME_ORIG = "SubSecTimeOriginal";
+ /** Type is int. */
+ public static final String TAG_SUBSEC_TIME_DIG = "SubSecTimeDigitized";
+
+
/**
* @hide
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index eec4960..a79dd04 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -1455,15 +1455,6 @@ final public class MediaCodec {
@Retention(RetentionPolicy.SOURCE)
public @interface BufferFlag {}
- private static class FrameRenderedInfo {
- public long mPresentationTimeUs;
- public long mNanoTime;
- public FrameRenderedInfo(long presentationTimeUs, long nanoTime) {
- mPresentationTimeUs = presentationTimeUs;
- mNanoTime = nanoTime;
- }
- }
-
private EventHandler mEventHandler;
private EventHandler mOnFrameRenderedHandler;
private EventHandler mCallbackHandler;
@@ -1503,10 +1494,16 @@ final public class MediaCodec {
}
case EVENT_FRAME_RENDERED:
synchronized (mListenerLock) {
- FrameRenderedInfo info = (FrameRenderedInfo)msg.obj;
- if (mOnFrameRenderedListener != null) {
+ Map<String, Object> map = (Map<String, Object>)msg.obj;
+ for (int i = 0; ; ++i) {
+ Object mediaTimeUs = map.get(i + "-media-time-us");
+ Object systemNano = map.get(i + "-system-nano");
+ if (mediaTimeUs == null || systemNano == null
+ || mOnFrameRenderedListener == null) {
+ break;
+ }
mOnFrameRenderedListener.onFrameRendered(
- mCodec, info.mPresentationTimeUs, info.mNanoTime);
+ mCodec, (long)mediaTimeUs, (long)systemNano);
}
break;
}
@@ -2362,26 +2359,9 @@ final public class MediaCodec {
info = mDequeuedOutputInfos.remove(index);
}
}
- // TODO
- // until codec and libgui supports callback, assume frame is rendered within 50 ms
- postRenderedCallback(render, info, 50 /* delayMs */);
releaseOutputBuffer(index, render, false /* updatePTS */, 0 /* dummy */);
}
- private void postRenderedCallback(boolean render, @Nullable BufferInfo info, long delayMs) {
- if (render && info != null) {
- synchronized (mListenerLock) {
- if (mOnFrameRenderedListener != null) {
- FrameRenderedInfo obj = new FrameRenderedInfo(
- info.presentationTimeUs, System.nanoTime() + delayMs * 1000000);
- Message msg = mOnFrameRenderedHandler.obtainMessage(
- EVENT_FRAME_RENDERED, obj);
- mOnFrameRenderedHandler.sendMessageDelayed(msg, delayMs);
- }
- }
- }
- }
-
/**
* If you are done with a buffer, use this call to update its surface timestamp
* and return it to the codec to render it on the output surface. If you
@@ -2440,12 +2420,6 @@ final public class MediaCodec {
info = mDequeuedOutputInfos.remove(index);
}
}
- // TODO
- // until codec and libgui supports callback, assume frame is rendered at the
- // render time or 16 ms from now, whichever is later.
- postRenderedCallback(
- true /* render */, info,
- Math.max(renderTimestampNs - System.nanoTime(), 16666666) / 1000000);
releaseOutputBuffer(
index, true /* render */, true /* updatePTS */, renderTimestampNs);
}
@@ -3049,9 +3023,12 @@ final public class MediaCodec {
} else if (mOnFrameRenderedHandler != null) {
mOnFrameRenderedHandler.removeMessages(EVENT_FRAME_RENDERED);
}
+ native_enableOnFrameRenderedListener(listener != null);
}
}
+ private native void native_enableOnFrameRenderedListener(boolean enable);
+
private EventHandler getEventHandlerOn(
@Nullable Handler handler, @NonNull EventHandler lastHandler) {
if (handler == null) {
diff --git a/media/java/android/media/midi/package.html b/media/java/android/media/midi/package.html
index 8b2bd16..673c4ba 100644
--- a/media/java/android/media/midi/package.html
+++ b/media/java/android/media/midi/package.html
@@ -10,27 +10,28 @@
<p>The Android MIDI package allows users to:</p>
<ul>
- <li> Connect a MIDI keyboard to Android to play a synthesizer or drive music apps.
- <li> Connect alternative MIDI controllers to Android.
- <li> Drive external MIDI synths from Android.
- <li> Drive external peripherals, lights, show control, etc from Android.
- <li> Generate music dynamically from games or music creation apps.
- <li> Generate MIDI messages in one app and send them to a second app.
- <li> Use an Android device running in <em>peripheral mode</em> as a multitouch controller connected to a laptop.
+ <li> Connect a MIDI keyboard to Android to play a synthesizer or drive music apps.</li>
+ <li> Connect alternative MIDI controllers to Android.</li>
+ <li> Drive external MIDI synths from Android.</li>
+ <li> Drive external peripherals, lights, show control, etc from Android.</li>
+ <li> Generate music dynamically from games or music creation apps.</li>
+ <li> Generate MIDI messages in one app and send them to a second app.</li>
+ <li> Use an Android device running in <em>peripheral mode</em> as a multitouch controller
+ connected to a laptop.</li>
</ul>
<h2 id=the_api_features_include>The API features include:</h2>
-
<ul>
<li> Enumeration of currently available devices. Information includes name, vendor,
-capabilities, etc.
- <li> Provide notification when MIDI devices are plugged in or unplugged.
- <li> Support efficient transmission of single or multiple short 1-3 byte MIDI
-messages.
- <li> Support transmission of arbitrary length data for SysEx, etc.
- <li> Timestamps to avoid jitter.
- <li> Support direction connection or &ldquo;patching&rdquo; of devices for lower latency.
+capabilities, etc.</li>
+ <li> Provide notification when MIDI devices are plugged in or unplugged.</li>
+ <li> Support efficient transmission of single or multiple short 1-3 byte MIDI messages.</li>
+ <li> Support transmission of arbitrary length data for SysEx, etc.</li>
+ <li> Timestamps to avoid jitter.</li>
+ <li> Support creation of <em>virtual MIDI devices</em> that can be connected to other devices.
+ An example might be a synthesizer app that can be controlled by a composing app.</li>
+ <li> Support direction connection or &ldquo;patching&rdquo; of devices for lower latency.</li>
</ul>
<h2 id=transports_supported>Transports Supported</h2>
@@ -65,6 +66,14 @@ the MidiService.</p>
<h1 id=writing_a_midi_application>Writing a MIDI Application</h1>
+<h2 id=manifest_feature>Declare Feature in Manifest</h2>
+
+<p>An app that requires the MIDI API should declare that in the AndroidManifest.xml file.
+Then the app will not appear in the Play Store for old devices that do not support the MIDI API.</p>
+
+<pre class=prettyprint>
+&lt;uses-feature android:name="android.software.midi" android:required="true"/>
+</pre>
<h2 id=the_midimanager>The MidiManager</h2>
@@ -132,11 +141,15 @@ String manufacturer = properties
<p>Other properties include PROPERTY_PRODUCT, PROPERTY_NAME,
PROPERTY_SERIAL_NUMBER</p>
-<p>You can get the names of the ports from a PortInfo object.</p>
+<p>You can get the names and types of the ports from a PortInfo object.
+The type will be either TYPE_INPUT or TYPE_OUTPUT.</p>
<pre class=prettyprint>
-PortInfo portInfo = info.getInputPortInfo(i);
-String portName = portInfo.getName();
+MidiDeviceInfo.PortInfo[] portInfos = info.getPorts();
+String portName = portInfos[0].getName();
+if (portInfos[0].getType() == MidiDeviceInfo.PortInfo.TYPE_INPUT) {
+ ...
+}
</pre>
@@ -196,8 +209,9 @@ consistent with the other audio and input timers.</p>
<p>Here we send a message with a timestamp 2 seconds in the future.</p>
<pre class=prettyprint>
+final long NANOS_PER_SECOND = 1000000000L;
long now = System.nanoTime();
-long future = now + (2 * 1000000000);
+long future = now + (2 * NANOS_PER_SECOND);
inputPort.send(buffer, offset, numBytes, future);
</pre>
@@ -263,7 +277,8 @@ AndroidManifest.xml file.</p>
<p>The details of the resource in this example is stored in
-&ldquo;res/xml/synth_device_info.xml&rdquo;.</p>
+&ldquo;res/xml/synth_device_info.xml&rdquo;. The port names that you
+declare in this file will be available from PortInfo.getName().</p>
<pre class=prettyprint>
&lt;devices>
@@ -288,6 +303,8 @@ import android.media.midi.MidiReceiver;
public class MidiSynthDeviceService extends MidiDeviceService {
private static final String TAG = "MidiSynthDeviceService";
private MySynthEngine mSynthEngine = new MySynthEngine();
+ private boolean synthStarted = false;
+
&#64;Override
public void onCreate() {
super.onCreate();
@@ -311,10 +328,12 @@ public class MidiSynthDeviceService extends MidiDeviceService {
*/
&#64;Override
public void onDeviceStatusChanged(MidiDeviceStatus status) {
- if (status.isInputPortOpen(0)) {
+ if (status.isInputPortOpen(0) && !synthStarted) {
mSynthEngine.start();
- } else {
+ synthStarted = true;
+ } else if (!status.isInputPortOpen(0) && synthStarted){
mSynthEngine.stop();
+ synthStarted = false;
}
}
}
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 93b8ec7..ce7f7e5 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -56,6 +56,7 @@ enum {
enum {
EVENT_CALLBACK = 1,
EVENT_SET_CALLBACK = 2,
+ EVENT_FRAME_RENDERED = 3,
};
static struct CryptoErrorCodes {
@@ -226,6 +227,18 @@ void JMediaCodec::deleteJavaObjects(JNIEnv *env) {
mByteBufferLimitMethodID = NULL;
}
+status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) {
+ if (enable) {
+ if (mOnFrameRenderedNotification == NULL) {
+ mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this);
+ }
+ } else {
+ mOnFrameRenderedNotification.clear();
+ }
+
+ return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification);
+}
+
status_t JMediaCodec::setCallback(jobject cb) {
if (cb != NULL) {
if (mCallbackNotification == NULL) {
@@ -728,6 +741,27 @@ void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
env->DeleteLocalRef(obj);
}
+void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
+ int32_t arg1 = 0, arg2 = 0;
+ jobject obj = NULL;
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ sp<AMessage> data;
+ CHECK(msg->findMessage("data", &data));
+
+ status_t err = ConvertMessageToMap(env, data, &obj);
+ if (err != OK) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return;
+ }
+
+ env->CallVoidMethod(
+ mObject, gFields.postEventFromNativeID,
+ EVENT_FRAME_RENDERED, arg1, arg2, obj);
+
+ env->DeleteLocalRef(obj);
+}
+
void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatCallbackNotify:
@@ -735,6 +769,11 @@ void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
handleCallback(msg);
break;
}
+ case kWhatFrameRendered:
+ {
+ handleFrameRenderedNotification(msg);
+ break;
+ }
default:
TRESPASS();
}
@@ -848,6 +887,22 @@ static jint throwExceptionAsNecessary(
}
}
+static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
+ JNIEnv *env,
+ jobject thiz,
+ jboolean enabled) {
+ sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+
+ if (codec == NULL) {
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
+ return;
+ }
+
+ status_t err = codec->enableOnFrameRenderedListener(enabled);
+
+ throwExceptionAsNecessary(env, err);
+}
+
static void android_media_MediaCodec_native_setCallback(
JNIEnv *env,
jobject thiz,
@@ -1744,6 +1799,9 @@ static JNINativeMethod gMethods[] = {
{ "native_setInputSurface", "(Landroid/view/Surface;)V",
(void *)android_media_MediaCodec_setInputSurface },
+ { "native_enableOnFrameRenderedListener", "(Z)V",
+ (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },
+
{ "native_setCallback",
"(Landroid/media/MediaCodec$Callback;)V",
(void *)android_media_MediaCodec_native_setCallback },
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index a4ed67b..6650cf9 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -46,6 +46,8 @@ struct JMediaCodec : public AHandler {
void registerSelf();
void release();
+ status_t enableOnFrameRenderedListener(jboolean enable);
+
status_t setCallback(jobject cb);
status_t configure(
@@ -116,11 +118,11 @@ protected:
virtual ~JMediaCodec();
virtual void onMessageReceived(const sp<AMessage> &msg);
- void handleCallback(const sp<AMessage> &msg);
private:
enum {
kWhatCallbackNotify,
+ kWhatFrameRendered,
};
jclass mClass;
@@ -139,6 +141,7 @@ private:
sp<MediaCodec> mCodec;
sp<AMessage> mCallbackNotification;
+ sp<AMessage> mOnFrameRenderedNotification;
status_t mInitStatus;
@@ -148,6 +151,8 @@ private:
void cacheJavaObjects(JNIEnv *env);
void deleteJavaObjects(JNIEnv *env);
+ void handleCallback(const sp<AMessage> &msg);
+ void handleFrameRenderedNotification(const sp<AMessage> &msg);
DISALLOW_EVIL_CONSTRUCTORS(JMediaCodec);
};
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index 96b72a2..fdc586b 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -92,6 +92,7 @@ static jint translateError(int code) {
}
}
+static Mutex sLock;
// ----------------------------------------------------------------------------
static void effectCallback(int event, void* user, void *info) {
@@ -182,6 +183,32 @@ effectCallback_Exit:
}
// ----------------------------------------------------------------------------
+
+static sp<AudioEffect> getAudioEffect(JNIEnv* env, jobject thiz)
+{
+ Mutex::Autolock l(sLock);
+ AudioEffect* const ae =
+ (AudioEffect*)env->GetLongField(thiz, fields.fidNativeAudioEffect);
+ return sp<AudioEffect>(ae);
+}
+
+static sp<AudioEffect> setAudioEffect(JNIEnv* env, jobject thiz,
+ const sp<AudioEffect>& ae)
+{
+ Mutex::Autolock l(sLock);
+ sp<AudioEffect> old =
+ (AudioEffect*)env->GetLongField(thiz, fields.fidNativeAudioEffect);
+ if (ae.get()) {
+ ae->incStrong((void*)setAudioEffect);
+ }
+ if (old != 0) {
+ old->decStrong((void*)setAudioEffect);
+ }
+ env->SetLongField(thiz, fields.fidNativeAudioEffect, (jlong)ae.get());
+ return old;
+}
+
+// ----------------------------------------------------------------------------
// This function gets some field IDs, which in turn causes class initialization.
// It is called from a static block in AudioEffect, which won't run until the
// first time an instance of this class is used.
@@ -257,7 +284,7 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t
ALOGV("android_media_AudioEffect_native_setup");
AudioEffectJniStorage* lpJniStorage = NULL;
int lStatus = AUDIOEFFECT_ERROR_NO_MEMORY;
- AudioEffect* lpAudioEffect = NULL;
+ sp<AudioEffect> lpAudioEffect;
jint* nId = NULL;
const char *typeStr = NULL;
const char *uuidStr = NULL;
@@ -272,6 +299,8 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t
ScopedUtfChars opPackageNameStr(env, opPackageName);
+ setAudioEffect(env, thiz, 0);
+
if (type != NULL) {
typeStr = env->GetStringUTFChars(type, NULL);
if (typeStr == NULL) { // Out of memory
@@ -324,7 +353,7 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t
&lpJniStorage->mCallbackData,
sessionId,
0);
- if (lpAudioEffect == NULL) {
+ if (lpAudioEffect == 0) {
ALOGE("Error creating AudioEffect");
goto setup_failure;
}
@@ -394,7 +423,7 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t
env->SetObjectArrayElement(javadesc, 0, jdesc);
- env->SetLongField(thiz, fields.fidNativeAudioEffect, (jlong)lpAudioEffect);
+ setAudioEffect(env, thiz, lpAudioEffect);
env->SetLongField(thiz, fields.fidJniData, (jlong)lpJniStorage);
@@ -407,12 +436,9 @@ setup_failure:
env->ReleasePrimitiveArrayCritical(jId, nId, 0);
}
- if (lpAudioEffect) {
- delete lpAudioEffect;
- }
- env->SetLongField(thiz, fields.fidNativeAudioEffect, 0);
-
if (lpJniStorage) {
+ env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_class);
+ env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_ref);
delete lpJniStorage;
}
env->SetLongField(thiz, fields.fidJniData, 0);
@@ -430,20 +456,20 @@ setup_failure:
// ----------------------------------------------------------------------------
-static void android_media_AudioEffect_native_finalize(JNIEnv *env, jobject thiz) {
- ALOGV("android_media_AudioEffect_native_finalize jobject: %p\n", thiz);
-
- // delete the AudioEffect object
- AudioEffect* lpAudioEffect = (AudioEffect *)env->GetLongField(
- thiz, fields.fidNativeAudioEffect);
- if (lpAudioEffect) {
- ALOGV("deleting AudioEffect: %p\n", lpAudioEffect);
- delete lpAudioEffect;
+static void android_media_AudioEffect_native_release(JNIEnv *env, jobject thiz) {
+ sp<AudioEffect> lpAudioEffect = setAudioEffect(env, thiz, 0);
+ if (lpAudioEffect == 0) {
+ return;
}
// delete the JNI data
- AudioEffectJniStorage* lpJniStorage = (AudioEffectJniStorage *)env->GetLongField(
- thiz, fields.fidJniData);
+ AudioEffectJniStorage* lpJniStorage =
+ (AudioEffectJniStorage *)env->GetLongField(thiz, fields.fidJniData);
+
+ // reset the native resources in the Java object so any attempt to access
+ // them after a call to release fails.
+ env->SetLongField(thiz, fields.fidJniData, 0);
+
if (lpJniStorage) {
ALOGV("deleting pJniStorage: %p\n", lpJniStorage);
delete lpJniStorage;
@@ -451,24 +477,16 @@ static void android_media_AudioEffect_native_finalize(JNIEnv *env, jobject thiz
}
// ----------------------------------------------------------------------------
-static void android_media_AudioEffect_native_release(JNIEnv *env, jobject thiz) {
-
- // do everything a call to finalize would
- android_media_AudioEffect_native_finalize(env, thiz);
- // + reset the native resources in the Java object so any attempt to access
- // them after a call to release fails.
- env->SetLongField(thiz, fields.fidNativeAudioEffect, 0);
- env->SetLongField(thiz, fields.fidJniData, 0);
+static void android_media_AudioEffect_native_finalize(JNIEnv *env, jobject thiz) {
+ ALOGV("android_media_AudioEffect_native_finalize jobject: %p\n", thiz);
+ android_media_AudioEffect_native_release(env, thiz);
}
static jint
android_media_AudioEffect_native_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled)
{
- // retrieve the AudioEffect object
- AudioEffect* lpAudioEffect = (AudioEffect *)env->GetLongField(
- thiz, fields.fidNativeAudioEffect);
-
- if (lpAudioEffect == NULL) {
+ sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
+ if (lpAudioEffect == 0) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioEffect pointer for enable()");
return AUDIOEFFECT_ERROR_NO_INIT;
@@ -480,11 +498,8 @@ android_media_AudioEffect_native_setEnabled(JNIEnv *env, jobject thiz, jboolean
static jboolean
android_media_AudioEffect_native_getEnabled(JNIEnv *env, jobject thiz)
{
- // retrieve the AudioEffect object
- AudioEffect* lpAudioEffect = (AudioEffect *)env->GetLongField(
- thiz, fields.fidNativeAudioEffect);
-
- if (lpAudioEffect == NULL) {
+ sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
+ if (lpAudioEffect == 0) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioEffect pointer for getEnabled()");
return JNI_FALSE;
@@ -501,11 +516,8 @@ android_media_AudioEffect_native_getEnabled(JNIEnv *env, jobject thiz)
static jboolean
android_media_AudioEffect_native_hasControl(JNIEnv *env, jobject thiz)
{
- // retrieve the AudioEffect object
- AudioEffect* lpAudioEffect = (AudioEffect *)env->GetLongField(
- thiz, fields.fidNativeAudioEffect);
-
- if (lpAudioEffect == NULL) {
+ sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
+ if (lpAudioEffect == 0) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioEffect pointer for hasControl()");
return JNI_FALSE;
@@ -528,10 +540,8 @@ static jint android_media_AudioEffect_native_setParameter(JNIEnv *env,
effect_param_t *p;
int voffset;
- AudioEffect* lpAudioEffect = (AudioEffect *) env->GetLongField(thiz,
- fields.fidNativeAudioEffect);
-
- if (lpAudioEffect == NULL) {
+ sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
+ if (lpAudioEffect == 0) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioEffect pointer for setParameter()");
return AUDIOEFFECT_ERROR_NO_INIT;
@@ -591,10 +601,8 @@ android_media_AudioEffect_native_getParameter(JNIEnv *env,
effect_param_t *p;
int voffset;
- AudioEffect* lpAudioEffect = (AudioEffect *) env->GetLongField(thiz,
- fields.fidNativeAudioEffect);
-
- if (lpAudioEffect == NULL) {
+ sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
+ if (lpAudioEffect == 0) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioEffect pointer for getParameter()");
return AUDIOEFFECT_ERROR_NO_INIT;
@@ -657,11 +665,8 @@ static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz,
jbyte* pReplyData = NULL;
jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
- // retrieve the AudioEffect object
- AudioEffect* lpAudioEffect = (AudioEffect *) env->GetLongField(thiz,
- fields.fidNativeAudioEffect);
-
- if (lpAudioEffect == NULL) {
+ sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
+ if (lpAudioEffect == 0) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioEffect pointer for setParameter()");
return AUDIOEFFECT_ERROR_NO_INIT;
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
index abc681e..6098b4a 100644
--- a/media/jni/audioeffect/android_media_Visualizer.cpp
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -102,14 +102,14 @@ struct visualizer_callback_cookie {
};
// ----------------------------------------------------------------------------
-class visualizerJniStorage {
+class VisualizerJniStorage {
public:
visualizer_callback_cookie mCallbackData;
- visualizerJniStorage() {
+ VisualizerJniStorage() {
}
- ~visualizerJniStorage() {
+ ~VisualizerJniStorage() {
}
};
@@ -135,6 +135,7 @@ static jint translateError(int code) {
}
}
+static Mutex sLock;
// ----------------------------------------------------------------------------
static void ensureArraySize(JNIEnv *env, jbyteArray *array, uint32_t size) {
@@ -227,15 +228,30 @@ static void captureCallback(void* user,
}
}
-static Visualizer *getVisualizer(JNIEnv* env, jobject thiz)
+// ----------------------------------------------------------------------------
+
+static sp<Visualizer> getVisualizer(JNIEnv* env, jobject thiz)
{
- Visualizer *v = (Visualizer *)env->GetLongField(
- thiz, fields.fidNativeVisualizer);
- if (v == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "Unable to retrieve Visualizer pointer");
+ Mutex::Autolock l(sLock);
+ Visualizer* const v =
+ (Visualizer*)env->GetLongField(thiz, fields.fidNativeVisualizer);
+ return sp<Visualizer>(v);
+}
+
+static sp<Visualizer> setVisualizer(JNIEnv* env, jobject thiz,
+ const sp<Visualizer>& v)
+{
+ Mutex::Autolock l(sLock);
+ sp<Visualizer> old =
+ (Visualizer*)env->GetLongField(thiz, fields.fidNativeVisualizer);
+ if (v.get()) {
+ v->incStrong((void*)setVisualizer);
+ }
+ if (old != 0) {
+ old->decStrong((void*)setVisualizer);
}
- return v;
+ env->SetLongField(thiz, fields.fidNativeVisualizer, (jlong)v.get());
+ return old;
}
// ----------------------------------------------------------------------------
@@ -318,7 +334,7 @@ static void android_media_visualizer_effect_callback(int32_t event,
void *info) {
if ((event == AudioEffect::EVENT_ERROR) &&
(*((status_t*)info) == DEAD_OBJECT)) {
- visualizerJniStorage* lpJniStorage = (visualizerJniStorage*)user;
+ VisualizerJniStorage* lpJniStorage = (VisualizerJniStorage*)user;
visualizer_callback_cookie* callbackInfo = &lpJniStorage->mCallbackData;
JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -336,14 +352,16 @@ android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
jint sessionId, jintArray jId, jstring opPackageName)
{
ALOGV("android_media_visualizer_native_setup");
- visualizerJniStorage* lpJniStorage = NULL;
+ VisualizerJniStorage* lpJniStorage = NULL;
int lStatus = VISUALIZER_ERROR_NO_MEMORY;
- Visualizer* lpVisualizer = NULL;
+ sp<Visualizer> lpVisualizer;
jint* nId = NULL;
ScopedUtfChars opPackageNameStr(env, opPackageName);
- lpJniStorage = new visualizerJniStorage();
+ setVisualizer(env, thiz, 0);
+
+ lpJniStorage = new VisualizerJniStorage();
if (lpJniStorage == NULL) {
ALOGE("setup: Error creating JNI Storage");
goto setup_failure;
@@ -371,7 +389,7 @@ android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
android_media_visualizer_effect_callback,
lpJniStorage,
sessionId);
- if (lpVisualizer == NULL) {
+ if (lpVisualizer == 0) {
ALOGE("Error creating Visualizer");
goto setup_failure;
}
@@ -392,7 +410,7 @@ android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
env->ReleasePrimitiveArrayCritical(jId, nId, 0);
nId = NULL;
- env->SetLongField(thiz, fields.fidNativeVisualizer, (jlong)lpVisualizer);
+ setVisualizer(env, thiz, lpVisualizer);
env->SetLongField(thiz, fields.fidJniData, (jlong)lpJniStorage);
@@ -405,12 +423,9 @@ setup_failure:
env->ReleasePrimitiveArrayCritical(jId, nId, 0);
}
- if (lpVisualizer) {
- delete lpVisualizer;
- }
- env->SetLongField(thiz, fields.fidNativeVisualizer, 0);
-
if (lpJniStorage) {
+ env->DeleteGlobalRef(lpJniStorage->mCallbackData.visualizer_class);
+ env->DeleteGlobalRef(lpJniStorage->mCallbackData.visualizer_ref);
delete lpJniStorage;
}
env->SetLongField(thiz, fields.fidJniData, 0);
@@ -419,49 +434,44 @@ setup_failure:
}
// ----------------------------------------------------------------------------
-static void android_media_visualizer_native_finalize(JNIEnv *env, jobject thiz) {
- ALOGV("android_media_visualizer_native_finalize jobject: %p\n", thiz);
-
- // delete the Visualizer object
- Visualizer* lpVisualizer = (Visualizer *)env->GetLongField(
- thiz, fields.fidNativeVisualizer);
- if (lpVisualizer) {
- ALOGV("deleting Visualizer: %p\n", lpVisualizer);
- delete lpVisualizer;
+static void android_media_visualizer_native_release(JNIEnv *env, jobject thiz) {
+ sp<Visualizer> lpVisualizer = setVisualizer(env, thiz, 0);
+ if (lpVisualizer == 0) {
+ return;
}
// delete the JNI data
- visualizerJniStorage* lpJniStorage = (visualizerJniStorage *)env->GetLongField(
- thiz, fields.fidJniData);
+ VisualizerJniStorage* lpJniStorage =
+ (VisualizerJniStorage *)env->GetLongField(thiz, fields.fidJniData);
+
+ // reset the native resources in the Java object so any attempt to access
+ // them after a call to release fails.
+ env->SetLongField(thiz, fields.fidJniData, 0);
+
if (lpJniStorage) {
ALOGV("deleting pJniStorage: %p\n", lpJniStorage);
delete lpJniStorage;
}
}
-// ----------------------------------------------------------------------------
-static void android_media_visualizer_native_release(JNIEnv *env, jobject thiz) {
-
- // do everything a call to finalize would
- android_media_visualizer_native_finalize(env, thiz);
- // + reset the native resources in the Java object so any attempt to access
- // them after a call to release fails.
- env->SetLongField(thiz, fields.fidNativeVisualizer, 0);
- env->SetLongField(thiz, fields.fidJniData, 0);
+static void android_media_visualizer_native_finalize(JNIEnv *env, jobject thiz) {
+ ALOGV("android_media_visualizer_native_finalize jobject: %p\n", thiz);
+ android_media_visualizer_native_release(env, thiz);
}
+// ----------------------------------------------------------------------------
static jint
android_media_visualizer_native_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled)
{
- Visualizer* lpVisualizer = getVisualizer(env, thiz);
- if (lpVisualizer == NULL) {
+ sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == 0) {
return VISUALIZER_ERROR_NO_INIT;
}
jint retVal = translateError(lpVisualizer->setEnabled(enabled));
if (!enabled) {
- visualizerJniStorage* lpJniStorage = (visualizerJniStorage *)env->GetLongField(
+ VisualizerJniStorage* lpJniStorage = (VisualizerJniStorage *)env->GetLongField(
thiz, fields.fidJniData);
if (NULL != lpJniStorage)
@@ -474,8 +484,8 @@ android_media_visualizer_native_setEnabled(JNIEnv *env, jobject thiz, jboolean e
static jboolean
android_media_visualizer_native_getEnabled(JNIEnv *env, jobject thiz)
{
- Visualizer* lpVisualizer = getVisualizer(env, thiz);
- if (lpVisualizer == NULL) {
+ sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == 0) {
return JNI_FALSE;
}
@@ -507,8 +517,8 @@ android_media_visualizer_native_getMaxCaptureRate(JNIEnv* /* env */, jobject /*
static jint
android_media_visualizer_native_setCaptureSize(JNIEnv *env, jobject thiz, jint size)
{
- Visualizer* lpVisualizer = getVisualizer(env, thiz);
- if (lpVisualizer == NULL) {
+ sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == 0) {
return VISUALIZER_ERROR_NO_INIT;
}
@@ -518,8 +528,8 @@ android_media_visualizer_native_setCaptureSize(JNIEnv *env, jobject thiz, jint s
static jint
android_media_visualizer_native_getCaptureSize(JNIEnv *env, jobject thiz)
{
- Visualizer* lpVisualizer = getVisualizer(env, thiz);
- if (lpVisualizer == NULL) {
+ sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == 0) {
return -1;
}
return (jint) lpVisualizer->getCaptureSize();
@@ -528,8 +538,8 @@ android_media_visualizer_native_getCaptureSize(JNIEnv *env, jobject thiz)
static jint
android_media_visualizer_native_setScalingMode(JNIEnv *env, jobject thiz, jint mode)
{
- Visualizer* lpVisualizer = getVisualizer(env, thiz);
- if (lpVisualizer == NULL) {
+ sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == 0) {
return VISUALIZER_ERROR_NO_INIT;
}
@@ -539,8 +549,8 @@ android_media_visualizer_native_setScalingMode(JNIEnv *env, jobject thiz, jint m
static jint
android_media_visualizer_native_getScalingMode(JNIEnv *env, jobject thiz)
{
- Visualizer* lpVisualizer = getVisualizer(env, thiz);
- if (lpVisualizer == NULL) {
+ sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == 0) {
return -1;
}
return (jint)lpVisualizer->getScalingMode();
@@ -549,8 +559,8 @@ android_media_visualizer_native_getScalingMode(JNIEnv *env, jobject thiz)
static jint
android_media_visualizer_native_setMeasurementMode(JNIEnv *env, jobject thiz, jint mode)
{
- Visualizer* lpVisualizer = getVisualizer(env, thiz);
- if (lpVisualizer == NULL) {
+ sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == 0) {
return VISUALIZER_ERROR_NO_INIT;
}
return translateError(lpVisualizer->setMeasurementMode(mode));
@@ -559,8 +569,8 @@ android_media_visualizer_native_setMeasurementMode(JNIEnv *env, jobject thiz, ji
static jint
android_media_visualizer_native_getMeasurementMode(JNIEnv *env, jobject thiz)
{
- Visualizer* lpVisualizer = getVisualizer(env, thiz);
- if (lpVisualizer == NULL) {
+ sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == 0) {
return MEASUREMENT_MODE_NONE;
}
return lpVisualizer->getMeasurementMode();
@@ -569,8 +579,8 @@ android_media_visualizer_native_getMeasurementMode(JNIEnv *env, jobject thiz)
static jint
android_media_visualizer_native_getSamplingRate(JNIEnv *env, jobject thiz)
{
- Visualizer* lpVisualizer = getVisualizer(env, thiz);
- if (lpVisualizer == NULL) {
+ sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == 0) {
return -1;
}
return (jint) lpVisualizer->getSamplingRate();
@@ -579,8 +589,8 @@ android_media_visualizer_native_getSamplingRate(JNIEnv *env, jobject thiz)
static jint
android_media_visualizer_native_getWaveForm(JNIEnv *env, jobject thiz, jbyteArray jWaveform)
{
- Visualizer* lpVisualizer = getVisualizer(env, thiz);
- if (lpVisualizer == NULL) {
+ sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == 0) {
return VISUALIZER_ERROR_NO_INIT;
}
@@ -597,8 +607,8 @@ android_media_visualizer_native_getWaveForm(JNIEnv *env, jobject thiz, jbyteArra
static jint
android_media_visualizer_native_getFft(JNIEnv *env, jobject thiz, jbyteArray jFft)
{
- Visualizer* lpVisualizer = getVisualizer(env, thiz);
- if (lpVisualizer == NULL) {
+ sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == 0) {
return VISUALIZER_ERROR_NO_INIT;
}
@@ -616,8 +626,8 @@ android_media_visualizer_native_getFft(JNIEnv *env, jobject thiz, jbyteArray jFf
static jint
android_media_visualizer_native_getPeakRms(JNIEnv *env, jobject thiz, jobject jPeakRmsObj)
{
- Visualizer* lpVisualizer = getVisualizer(env, thiz);
- if (lpVisualizer == NULL) {
+ sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == 0) {
return VISUALIZER_ERROR_NO_INIT;
}
int32_t measurements[2];
@@ -635,11 +645,11 @@ android_media_visualizer_native_getPeakRms(JNIEnv *env, jobject thiz, jobject jP
static jint
android_media_setPeriodicCapture(JNIEnv *env, jobject thiz, jint rate, jboolean jWaveform, jboolean jFft)
{
- Visualizer* lpVisualizer = getVisualizer(env, thiz);
- if (lpVisualizer == NULL) {
+ sp<Visualizer> lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == 0) {
return VISUALIZER_ERROR_NO_INIT;
}
- visualizerJniStorage* lpJniStorage = (visualizerJniStorage *)env->GetLongField(thiz,
+ VisualizerJniStorage* lpJniStorage = (VisualizerJniStorage *)env->GetLongField(thiz,
fields.fidJniData);
if (lpJniStorage == NULL) {
return VISUALIZER_ERROR_NO_INIT;