Loading media/java/android/media/AudioAttributes.java +7 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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: Loading media/java/android/media/AudioManager.java +5 −1 Original line number Diff line number Diff line Loading @@ -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; Loading media/java/android/media/AudioService.java +49 −10 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -5634,31 +5639,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); Loading @@ -5668,27 +5675,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 } media/java/android/media/IAudioService.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -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); } media/java/android/media/audiopolicy/AudioMix.java +12 −1 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -39,6 +40,7 @@ public class AudioMix { mRule = rule; mFormat = format; mRouteFlags = routeFlags; mRegistrationId = null; } /** Loading @@ -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 Loading
media/java/android/media/AudioAttributes.java +7 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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: Loading
media/java/android/media/AudioManager.java +5 −1 Original line number Diff line number Diff line Loading @@ -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; Loading
media/java/android/media/AudioService.java +49 −10 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -5634,31 +5639,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); Loading @@ -5668,27 +5675,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 }
media/java/android/media/IAudioService.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -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); }
media/java/android/media/audiopolicy/AudioMix.java +12 −1 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -39,6 +40,7 @@ public class AudioMix { mRule = rule; mFormat = format; mRouteFlags = routeFlags; mRegistrationId = null; } /** Loading @@ -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