Loading media/java/android/media/AudioService.java +7 −1 Original line number Diff line number Diff line Loading @@ -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(); Loading media/java/android/media/SoundPool.java +68 −8 Original line number Diff line number Diff line Loading @@ -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); } } Loading Loading @@ -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 Loading @@ -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); } Loading Loading @@ -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; Loading Loading @@ -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(); } } Loading media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp +62 −13 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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; } Loading @@ -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; } Loading Loading @@ -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", Loading @@ -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 Loading @@ -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; /* success -- return valid version number */ result = JNI_VERSION_1_4; return result; bail: // 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; } /* success -- return valid version number */ return JNI_VERSION_1_4; } Loading
media/java/android/media/AudioService.java +7 −1 Original line number Diff line number Diff line Loading @@ -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(); Loading
media/java/android/media/SoundPool.java +68 −8 Original line number Diff line number Diff line Loading @@ -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); } } Loading Loading @@ -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 Loading @@ -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); } Loading Loading @@ -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; Loading Loading @@ -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(); } } Loading
media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp +62 −13 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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; } Loading @@ -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; } Loading Loading @@ -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", Loading @@ -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 Loading @@ -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; /* success -- return valid version number */ result = JNI_VERSION_1_4; return result; bail: // 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; } /* success -- return valid version number */ return JNI_VERSION_1_4; }