diff options
| author | Jean-Michel Trivi <jmtrivi@google.com> | 2014-07-20 17:56:11 -0700 |
|---|---|---|
| committer | Jean-Michel Trivi <jmtrivi@google.com> | 2014-07-20 18:12:00 -0700 |
| commit | 55a30c41b6c47d3afe6b13c25c64e8eec9f45e7c (patch) | |
| tree | b4dd245b8cc49afa209e2895a003779c8aeccc58 | |
| parent | 7226b9b62d9c26eda9e2353e8ce35808e51c3fd3 (diff) | |
AudioAttributes for SoundPool
Add support for building a SoundPool instance and specify
the AudioAttributes.
Remove SRC quality which was never implemented, while leaving
room for supporting it later through the Builder pattern.
Remove stream types.
Update AudioService's use of SoundPool to the new scheme.
Change-Id: Ie51e4008684e5ba25f9b7368098e4f20266a15c7
| -rw-r--r-- | media/java/android/media/AudioService.java | 8 | ||||
| -rw-r--r-- | media/java/android/media/SoundPool.java | 76 | ||||
| -rw-r--r-- | media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp | 75 |
3 files changed, 137 insertions, 22 deletions
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index b01323c1c14c..e94f8c1910a2 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -3500,7 +3500,13 @@ public class AudioService extends IAudioService.Stub { loadTouchSoundAssets(); - mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0); + mSoundPool = new SoundPool.Builder() + .setMaxStreams(NUM_SOUNDPOOL_CHANNELS) + .setAudioAttributes(new AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .build()) + .build(); mSoundPoolCallBack = null; mSoundPoolListenerThread = new SoundPoolListenerThread(); mSoundPoolListenerThread.start(); diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java index 44c193fe5a47..56079ad42c72 100644 --- a/media/java/android/media/SoundPool.java +++ b/media/java/android/media/SoundPool.java @@ -128,10 +128,69 @@ public class SoundPool { * @return a SoundPool object, or null if creation failed */ public SoundPool(int maxStreams, int streamType, int srcQuality) { + this(maxStreams, + new AudioAttributes.Builder().setInternalLegacyStreamType(streamType).build()); + } + + private SoundPool(int maxStreams, AudioAttributes attributes) { if (SystemProperties.getBoolean("config.disable_media", false)) { mImpl = new SoundPoolStub(); } else { - mImpl = new SoundPoolImpl(this, maxStreams, streamType, srcQuality); + mImpl = new SoundPoolImpl(this, maxStreams, attributes); + } + } + + /** + * @hide + * CANDIDATE FOR PUBLIC API + * Builder class for {@link SoundPool} objects. + */ + public static class Builder { + private int mMaxStreams = 1; + private AudioAttributes mAudioAttributes; + + /** + * Constructs a new Builder with the defaults format values. + */ + public Builder() { + } + + /** + * Sets the maximum of number of simultaneous streams that can be played simultaneously. + * @param maxStreams a value equal to 1 or greater. + * @return the same Builder instance + * @throws IllegalArgumentException + */ + public Builder setMaxStreams(int maxStreams) throws IllegalArgumentException { + if (maxStreams <= 0) { + throw new IllegalArgumentException( + "Strictly position value required for the maximum number of streams"); + } + mMaxStreams = maxStreams; + return this; + } + + /** + * Sets the {@link AudioAttributes}. For examples, game applications will use attributes + * built with usage information set to {@link AudioAttributes#USAGE_GAME}. + * @param attributes a non-null + * @return + */ + public Builder setAudioAttributes(AudioAttributes attributes) + throws IllegalArgumentException { + if (attributes == null) { + throw new IllegalArgumentException("Invalid null AudioAttributes"); + } + mAudioAttributes = attributes; + return this; + } + + public SoundPool build() { + if (mAudioAttributes == null) { + mAudioAttributes = new AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_MEDIA).build(); + } + return new SoundPool(mMaxStreams, mAudioAttributes); } } @@ -457,7 +516,7 @@ public class SoundPool { private SoundPool mProxy; private final Object mLock; - private final int mStreamType; + private final AudioAttributes mAttributes; private final IAppOpsService mAppOps; // SoundPool messages @@ -465,15 +524,15 @@ public class SoundPool { // must match SoundPool.h private static final int SAMPLE_LOADED = 1; - public SoundPoolImpl(SoundPool proxy, int maxStreams, int streamType, int srcQuality) { + public SoundPoolImpl(SoundPool proxy, int maxStreams, AudioAttributes attr) { // do native setup - if (native_setup(new WeakReference(this), maxStreams, streamType, srcQuality) != 0) { + if (native_setup(new WeakReference(this), maxStreams, attr) != 0) { throw new RuntimeException("Native setup failed"); } mLock = new Object(); mProxy = proxy; - mStreamType = streamType; + mAttributes = attr; IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE); mAppOps = IAppOpsService.Stub.asInterface(b); } @@ -548,9 +607,9 @@ public class SoundPool { private boolean isRestricted() { try { - final int usage = AudioAttributes.usageForLegacyStreamType(mStreamType); final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO, - usage, Process.myUid(), ActivityThread.currentPackageName()); + mAttributes.getUsage(), + Process.myUid(), ActivityThread.currentPackageName()); return mode != AppOpsManager.MODE_ALLOWED; } catch (RemoteException e) { return false; @@ -648,7 +707,8 @@ public class SoundPool { public native final void release(); - private native final int native_setup(Object weakRef, int maxStreams, int streamType, int srcQuality); + private native final int native_setup(Object weakRef, int maxStreams, + Object/*AudioAttributes*/ attributes); protected void finalize() { release(); } } diff --git a/media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp b/media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp index bda3b6bd3f8a..89b2893a648a 100644 --- a/media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp +++ b/media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp @@ -32,10 +32,17 @@ static struct fields_t { jmethodID mPostEvent; jclass mSoundPoolClass; } fields; - static inline SoundPool* MusterSoundPool(JNIEnv *env, jobject thiz) { return (SoundPool*)env->GetLongField(thiz, fields.mNativeContext); } +static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes"; +struct audio_attributes_fields_t { + jfieldID fieldUsage; // AudioAttributes.mUsage + jfieldID fieldContentType; // AudioAttributes.mContentType + jfieldID fieldFlags; // AudioAttributes.mFlags + jfieldID fieldFormattedTags;// AudioAttributes.mFormattedTags +}; +static audio_attributes_fields_t javaAudioAttrFields; // ---------------------------------------------------------------------------- static jint @@ -176,10 +183,30 @@ static void android_media_callback(SoundPoolEvent event, SoundPool* soundPool, v } static jint -android_media_SoundPool_SoundPoolImpl_native_setup(JNIEnv *env, jobject thiz, jobject weakRef, jint maxChannels, jint streamType, jint srcQuality) +android_media_SoundPool_SoundPoolImpl_native_setup(JNIEnv *env, jobject thiz, jobject weakRef, + jint maxChannels, jobject jaa) { + if (jaa == 0) { + ALOGE("Error creating SoundPool: invalid audio attributes"); + return -1; + } + + audio_attributes_t *paa = NULL; + // read the AudioAttributes values + paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t)); + const jstring jtags = + (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags); + const char* tags = env->GetStringUTFChars(jtags, NULL); + // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it + strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1); + env->ReleaseStringUTFChars(jtags, tags); + paa->usage = (audio_usage_t) env->GetIntField(jaa, javaAudioAttrFields.fieldUsage); + paa->content_type = + (audio_content_type_t) env->GetIntField(jaa, javaAudioAttrFields.fieldContentType); + paa->flags = env->GetIntField(jaa, javaAudioAttrFields.fieldFlags); + ALOGV("android_media_SoundPool_SoundPoolImpl_native_setup"); - SoundPool *ap = new SoundPool(maxChannels, (audio_stream_type_t) streamType, srcQuality); + SoundPool *ap = new SoundPool(maxChannels, paa); if (ap == NULL) { return -1; } @@ -190,6 +217,10 @@ android_media_SoundPool_SoundPoolImpl_native_setup(JNIEnv *env, jobject thiz, jo // set callback with weak reference jobject globalWeakRef = env->NewGlobalRef(weakRef); ap->setCallback(android_media_callback, globalWeakRef); + + // audio attributes were copied in SoundPool creation + free(paa); + return 0; } @@ -270,7 +301,7 @@ static JNINativeMethod gMethods[] = { (void *)android_media_SoundPool_SoundPoolImpl_setRate }, { "native_setup", - "(Ljava/lang/Object;III)I", + "(Ljava/lang/Object;ILjava/lang/Object;)I", (void*)android_media_SoundPool_SoundPoolImpl_native_setup }, { "release", @@ -289,27 +320,27 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { ALOGE("ERROR: GetEnv failed\n"); - goto bail; + return result; } assert(env != NULL); clazz = env->FindClass(kClassPathName); if (clazz == NULL) { ALOGE("Can't find %s", kClassPathName); - goto bail; + return result; } fields.mNativeContext = env->GetFieldID(clazz, "mNativeContext", "J"); if (fields.mNativeContext == NULL) { ALOGE("Can't find SoundPoolImpl.mNativeContext"); - goto bail; + return result; } fields.mPostEvent = env->GetStaticMethodID(clazz, "postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)V"); if (fields.mPostEvent == NULL) { ALOGE("Can't find android/media/SoundPoolImpl.postEventFromNative"); - goto bail; + return result; } // create a reference to class. Technically, we're leaking this reference @@ -317,11 +348,29 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) fields.mSoundPoolClass = (jclass) env->NewGlobalRef(clazz); if (AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)) < 0) - goto bail; + return result; - /* success -- return valid version number */ - result = JNI_VERSION_1_4; + // Get the AudioAttributes class and fields + jclass audioAttrClass = env->FindClass(kAudioAttributesClassPathName); + if (audioAttrClass == NULL) { + ALOGE("Can't find %s", kAudioAttributesClassPathName); + return result; + } + jclass audioAttributesClassRef = (jclass)env->NewGlobalRef(audioAttrClass); + javaAudioAttrFields.fieldUsage = env->GetFieldID(audioAttributesClassRef, "mUsage", "I"); + javaAudioAttrFields.fieldContentType + = env->GetFieldID(audioAttributesClassRef, "mContentType", "I"); + javaAudioAttrFields.fieldFlags = env->GetFieldID(audioAttributesClassRef, "mFlags", "I"); + javaAudioAttrFields.fieldFormattedTags = + env->GetFieldID(audioAttributesClassRef, "mFormattedTags", "Ljava/lang/String;"); + env->DeleteGlobalRef(audioAttributesClassRef); + if (javaAudioAttrFields.fieldUsage == NULL || javaAudioAttrFields.fieldContentType == NULL + || javaAudioAttrFields.fieldFlags == NULL + || javaAudioAttrFields.fieldFormattedTags == NULL) { + ALOGE("Can't initialize AudioAttributes fields"); + return result; + } -bail: - return result; + /* success -- return valid version number */ + return JNI_VERSION_1_4; } |
