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

Commit 8fdb0d4d authored by Jean-Michel Trivi's avatar Jean-Michel Trivi
Browse files

More AudioPolicy registration

Define new usage in AudioAttributes to describe "virtual" sources.
Maintain a registration string in AudioPolicy and AudioMix that
 is used for the address of the mix in the native policy manager.
AudioPolicy registration marks the audio policy configuration and
 the audio mixes as registered.
The AudioPolicy class is used as the factory for the AudioTrack
 and AudioRecord objects that are respectively used as the
 source and sink of the mixes created by the policy owner.

Bug 16009464

Change-Id: I8e5bd351495257597c513d22597e273fcabdbc55
parent ba9836d9
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -161,6 +161,12 @@ public final class AudioAttributes implements Parcelable {
     * Usage value to use when the usage is for game audio.
     */
    public final static int USAGE_GAME = 14;
    /**
     * @hide
     * Usage value to use when feeding audio to the platform and replacing "traditional" audio
     * source, such as audio capture devices.
     */
    public final static int USAGE_VIRTUAL_SOURCE = 15;

    /**
     * Flag defining a behavior where the audibility of the sound will be ensured by the system.
@@ -374,6 +380,7 @@ public final class AudioAttributes implements Parcelable {
                case USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
                case USAGE_ASSISTANCE_SONIFICATION:
                case USAGE_GAME:
                case USAGE_VIRTUAL_SOURCE:
                     mUsage = usage;
                     break;
                default:
+5 −1
Original line number Diff line number Diff line
@@ -2663,9 +2663,13 @@ public class AudioManager {
        }
        IAudioService service = getService();
        try {
            if (!service.registerAudioPolicy(policy.getConfig(), policy.token())) {
            String regId = service.registerAudioPolicy(policy.getConfig(), policy.token());
            if (regId == null) {
                return ERROR;
            } else {
                policy.setRegistration(regId);
            }
            // successful registration
        } catch (RemoteException e) {
            Log.e(TAG, "Dead object in registerAudioPolicyAsync()", e);
            return ERROR;
+49 −10
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ import android.hardware.hdmi.HdmiTvClient;
import android.hardware.usb.UsbManager;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.audiopolicy.AudioMix;
import android.media.audiopolicy.AudioPolicyConfig;
import android.media.session.MediaSessionLegacyHelper;
import android.os.Binder;
@@ -118,6 +119,10 @@ public class AudioService extends IAudioService.Stub {

    /** Debug audio mode */
    protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);

    /** Debug audio policy feature */
    protected static final boolean DEBUG_AP = Log.isLoggable(TAG + ".AP", Log.DEBUG);

    /** Debug volumes */
    protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);

@@ -5630,31 +5635,33 @@ public class AudioService extends IAudioService.Stub {
    //==========================================================================================
    // Audio policy management
    //==========================================================================================
    public boolean registerAudioPolicy(AudioPolicyConfig policyConfig, IBinder cb) {
    public String registerAudioPolicy(AudioPolicyConfig policyConfig, IBinder cb) {
        //Log.v(TAG, "registerAudioPolicy for " + cb + " got policy:" + policyConfig);
        String regId = null;
        boolean hasPermissionForPolicy =
                (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
                        android.Manifest.permission.MODIFY_AUDIO_ROUTING));
        if (!hasPermissionForPolicy) {
            Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
                    + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
            return false;
            return null;
        }
        synchronized (mAudioPolicies) {
            AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, cb);
            try {
                AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, cb);
                cb.linkToDeath(app, 0/*flags*/);
                regId = app.connectMixes();
                mAudioPolicies.put(cb, app);
            } catch (RemoteException e) {
                // audio policy owner has already died!
                Slog.w(TAG, "Audio policy registration failed, could not link to " + cb +
                        " binder death", e);
                return false;
                return null;
            }
        }
        // TODO implement registration with native audio policy (including permission check)
        return true;
        return regId;
    }

    public void unregisterAudioPolicyAsync(IBinder cb) {
        synchronized (mAudioPolicies) {
            AudioPolicyProxy app = mAudioPolicies.remove(cb);
@@ -5664,27 +5671,59 @@ public class AudioService extends IAudioService.Stub {
            } else {
                cb.unlinkToDeath(app, 0/*flags*/);
            }
            app.disconnectMixes();
        }
        // TODO implement registration with native audio policy
        // TODO implement clearing mix attribute matching info in native audio policy
    }

    public class AudioPolicyProxy implements IBinder.DeathRecipient {
    /**
     * This internal class inherits from AudioPolicyConfig which contains all the mixes and
     * their configurations.
     */
    public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
        private static final String TAG = "AudioPolicyProxy";
        AudioPolicyConfig mConfig;
        IBinder mToken;
        AudioPolicyProxy(AudioPolicyConfig config, IBinder token) {
            mConfig = config;
            super(config);
            setRegistration(new String(config.toString() + ":ap:" + mAudioPolicyCounter++));
            mToken = token;
        }

        public void binderDied() {
            synchronized (mAudioPolicies) {
                Log.v(TAG, "audio policy " + mToken + " died");
                Log.i(TAG, "audio policy " + mToken + " died");
                mAudioPolicies.remove(mToken);
                disconnectMixes();
            }
        }

        String connectMixes() {
            updateMixes(AudioSystem.DEVICE_STATE_AVAILABLE);
            return mRegistrationId;
        }

        void disconnectMixes() {
            updateMixes(AudioSystem.DEVICE_STATE_UNAVAILABLE);
        }

        void updateMixes(int connectionState) {
            for (AudioMix mix : mMixes) {
                // TODO implement sending the mix attribute matching info to native audio policy
                if (DEBUG_AP) {
                    Log.v(TAG, "AudioPolicyProxy connect mix state=" + connectionState
                            + " addr=" + mix.getRegistration()); }
                AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_REMOTE_SUBMIX,
                        connectionState,
                        mix.getRegistration());
                AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX,
                        connectionState,
                        mix.getRegistration());
            }
        }
    };

    private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
            new HashMap<IBinder, AudioPolicyProxy>();
    private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
}
+1 −1
Original line number Diff line number Diff line
@@ -207,6 +207,6 @@ interface IAudioService {

    boolean isHdmiSystemAudioSupported();

    boolean registerAudioPolicy(in AudioPolicyConfig policyConfig, IBinder cb);
           String registerAudioPolicy(in AudioPolicyConfig policyConfig, IBinder cb);
    oneway void unregisterAudioPolicyAsync(in IBinder cb);
}
+12 −1
Original line number Diff line number Diff line
@@ -24,13 +24,14 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * @hide CANDIDATE FOR PUBLIC API
 * @hide
 */
public class AudioMix {

    private AudioMixingRule mRule;
    private AudioFormat mFormat;
    private int mRouteFlags;
    private String mRegistrationId;

    /**
     * All parameters are guaranteed valid through the Builder.
@@ -39,6 +40,7 @@ public class AudioMix {
        mRule = rule;
        mFormat = format;
        mRouteFlags = routeFlags;
        mRegistrationId = null;
    }

    /**
@@ -65,6 +67,15 @@ public class AudioMix {
        return mRule;
    }

    void setRegistration(String regId) {
        mRegistrationId = regId;
    }

    /** @hide */
    public String getRegistration() {
        return mRegistrationId;
    }

    /** @hide */
    @IntDef(flag = true,
            value = { ROUTE_FLAG_RENDER, ROUTE_FLAG_LOOP_BACK } )
Loading