Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 971cac75 authored by Ari Hausman-Cohen's avatar Ari Hausman-Cohen Committed by Android (Google) Code Review
Browse files

Merge changes from topic "dynamic_stream_effects_master"

* changes:
  Add Dynamic Stream Effects
  Add permission for dynamic AudioEffect attachment
parents c8280ca8 7d54c5d8
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -3256,6 +3256,13 @@
    <permission android:name="android.permission.MODIFY_AUDIO_ROUTING"
        android:protectionLevel="signature|privileged" />

    <!-- Allows an application to modify what effects are applied to all audio
         (matching certain criteria) from any application.
         <p>Not for use by third-party applications.</p>
         @hide -->
    <permission android:name="android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"
        android:protectionLevel="signature|privileged" />

    <!-- @SystemApi Allows an application to capture video output.
         <p>Not for use by third-party applications.</p> -->
    <permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"
+40 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.media.audiofx;

/**
 * DefaultEffect is the base class for controlling default audio effects linked into the
 * Android audio framework.
 * <p>DefaultEffects are effects that get attached automatically to all AudioTracks,
 * AudioRecords, and MediaPlayer instances meeting some criteria.
 * <p>Applications should not use the DefaultEffect class directly but one of its derived classes
 * to control specific types of defaults:
 * <ul>
 *   <li> {@link android.media.audiofx.StreamDefaultEffect}</li>
 * </ul>
 * <p>Creating a DefaultEffect object will register the corresponding effect engine as a default
 * for the specified criteria. Whenever an audio session meets the criteria, an AudioEffect will
 * be created and attached to it using the specified priority.
 * @hide
 */

public abstract class DefaultEffect {
    /**
     * System wide unique default effect ID.
     */
    int mId;
}
+117 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.media.audiofx;

import android.annotation.RequiresPermission;
import android.app.ActivityThread;
import android.util.Log;
import java.util.UUID;

/**
 * StreamDefaultEffect is a default effect that attaches automatically to all AudioTracks and
 * MediaPlayer instances of a given stream type.
 * <p>see {@link android.media.audiofx.DefaultEffect} class for more details on default effects.
 * @hide
 */

public class StreamDefaultEffect extends DefaultEffect {
    static {
        System.loadLibrary("audioeffect_jni");
    }

    private final static String TAG = "StreamDefaultEffect-JAVA";

    /**
     * Class constructor.
     *
     * @param type type of effect engine to be default. This parameter is ignored if uuid is set,
     *             and can be set to {@link android.media.audiofx.AudioEffect#EFFECT_TYPE_NULL}
     *             in that case.
     * @param uuid unique identifier of a particular effect implementation to be default. This
     *             parameter can be set to
     *             {@link android.media.audiofx.AudioEffect#EFFECT_TYPE_NULL}, in which case only
     *             the type will be used to select the effect.
     * @param priority the priority level requested by the application for controlling the effect
     *             engine. As the same engine can be shared by several applications, this parameter
     *             indicates how much the requesting application needs control of effect parameters.
     *             The normal priority is 0, above normal is a positive number, below normal a
     *             negative number.
     * @param streamUsage a USAGE_* constant from {@link android.media.AudioAttributes} indicating
     *             what streams the given effect should attach to by default. Note that similar
     *             usages may share defaults.
     *
     * @throws java.lang.IllegalArgumentException
     * @throws java.lang.UnsupportedOperationException
     * @throws java.lang.RuntimeException
     */
    @RequiresPermission(value = android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS,
                        conditional = true)  // Android Things uses an alternate permission.
    public StreamDefaultEffect(UUID type, UUID uuid, int priority, int streamUsage) {
        int[] id = new int[1];
        int initResult = native_setup(type.toString(),
                                      uuid.toString(),
                                      priority,
                                      streamUsage,
                                      ActivityThread.currentOpPackageName(),
                                      id);
        if (initResult != AudioEffect.SUCCESS) {
            Log.e(TAG, "Error code " + initResult + " when initializing StreamDefaultEffect");
            switch (initResult) {
                case AudioEffect.ERROR_BAD_VALUE:
                    throw (new IllegalArgumentException(
                            "Stream usage, type uuid, or implementation uuid not supported."));
                case AudioEffect.ERROR_INVALID_OPERATION:
                    throw (new UnsupportedOperationException(
                            "Effect library not loaded"));
                default:
                    throw (new RuntimeException(
                            "Cannot initialize effect engine for type: " + type
                            + " Error: " + initResult));
            }
        }

        mId = id[0];
    }


    /**
     * Releases the native StreamDefaultEffect resources. It is a good practice to
     * release the default effect when done with use as control can be returned to
     * other applications or the native resources released.
     */
    public void release() {
        native_release(mId);
    }

    @Override
    protected void finalize() {
        release();
    }

    // ---------------------------------------------------------
    // Native methods called from the Java side
    // --------------------

    private native final int native_setup(String type,
                                          String uuid,
                                          int priority,
                                          int streamUsage,
                                          String opPackageName,
                                          int[] id);

    private native final void native_release(int id);
}
+1 −0
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@ cc_library_shared {

    srcs: [
        "android_media_AudioEffect.cpp",
        "android_media_StreamDefaultEffect.cpp",
        "android_media_Visualizer.cpp",
    ],

+23 −11
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@
 * limitations under the License.
 */

#include "android_media_AudioEffect.h"

#include <stdio.h>

//#define LOG_NDEBUG 0
@@ -71,7 +73,7 @@ class AudioEffectJniStorage {
};


static jint translateError(int code) {
jint AudioEffectJni::translateNativeErrorToJava(int code) {
    switch(code) {
    case NO_ERROR:
        return AUDIOEFFECT_SUCCESS;
@@ -81,6 +83,10 @@ static jint translateError(int code) {
        return AUDIOEFFECT_ERROR_NO_INIT;
    case BAD_VALUE:
        return AUDIOEFFECT_ERROR_BAD_VALUE;
    case NAME_NOT_FOUND:
        // Name not found means the client tried to create an effect not found on the system,
        // which is a form of bad value.
        return AUDIOEFFECT_ERROR_BAD_VALUE;
    case INVALID_OPERATION:
        return AUDIOEFFECT_ERROR_INVALID_OPERATION;
    case NO_MEMORY:
@@ -359,7 +365,7 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t
        goto setup_failure;
    }

    lStatus = translateError(lpAudioEffect->initCheck());
    lStatus = AudioEffectJni::translateNativeErrorToJava(lpAudioEffect->initCheck());
    if (lStatus != AUDIOEFFECT_SUCCESS && lStatus != AUDIOEFFECT_ERROR_ALREADY_EXISTS) {
        ALOGE("AudioEffect initCheck failed %d", lStatus);
        goto setup_failure;
@@ -495,7 +501,7 @@ android_media_AudioEffect_native_setEnabled(JNIEnv *env, jobject thiz, jboolean
        return AUDIOEFFECT_ERROR_NO_INIT;
    }

    return (jint) translateError(lpAudioEffect->setEnabled(enabled));
    return AudioEffectJni::translateNativeErrorToJava(lpAudioEffect->setEnabled(enabled));
}

static jboolean
@@ -590,7 +596,7 @@ setParameter_Exit:
    if (lpValue != NULL) {
        env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
    }
    return (jint) translateError(lStatus);
    return AudioEffectJni::translateNativeErrorToJava(lStatus);
}

static jint
@@ -658,7 +664,7 @@ getParameter_Exit:
    if (lStatus == NO_ERROR) {
        return vsize;
    }
    return (jint) translateError(lStatus);
    return AudioEffectJni::translateNativeErrorToJava(lStatus);
}

static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz,
@@ -697,7 +703,8 @@ static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz,
        }
    }

    lStatus = translateError(lpAudioEffect->command((uint32_t)cmdCode,
    lStatus = AudioEffectJni::translateNativeErrorToJava(
            lpAudioEffect->command((uint32_t)cmdCode,
                                   (uint32_t)cmdSize,
                                   pCmdData,
                                   (uint32_t *)&replySize,
@@ -900,6 +907,7 @@ static const JNINativeMethod gMethods[] = {

// ----------------------------------------------------------------------------

extern int register_android_media_StreamDefaultEffect(JNIEnv *env);
extern int register_android_media_visualizer(JNIEnv *env);

int register_android_media_AudioEffect(JNIEnv *env)
@@ -924,6 +932,11 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved __unused)
        goto bail;
    }

    if (register_android_media_StreamDefaultEffect(env) < 0) {
        ALOGE("ERROR: StreamDefaultEffect native registration failed\n");
        goto bail;
    }

    if (register_android_media_visualizer(env) < 0) {
        ALOGE("ERROR: Visualizer native registration failed\n");
        goto bail;
@@ -935,4 +948,3 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved __unused)
bail:
    return result;
}
Loading