FileDocCategorySizeDatePackage
AudioPolicy.javaAPI DocAndroid 5.1 API19770Thu Mar 12 22:22:30 GMT 2015android.media.audiopolicy

AudioPolicy

public class AudioPolicy extends Object
hide
AudioPolicy provides access to the management of audio routing and audio focus.

Fields Summary
private static final String
TAG
private static final boolean
DEBUG
private final Object
mLock
public static final int
POLICY_STATUS_UNREGISTERED
The status of an audio policy that is valid but cannot be used because it is not registered.
public static final int
POLICY_STATUS_REGISTERED
The status of an audio policy that is valid, successfully registered and thus active.
private int
mStatus
private String
mRegistrationId
private AudioPolicyStatusListener
mStatusListener
public static final int
FOCUS_POLICY_DUCKING_IN_APP
The behavior of a policy with regards to audio focus where it relies on the application to do the ducking, the is the legacy and default behavior.
public static final int
FOCUS_POLICY_DUCKING_DEFAULT
public static final int
FOCUS_POLICY_DUCKING_IN_POLICY
The behavior of a policy with regards to audio focus where it handles ducking instead of the application losing focus and being signaled it can duck (as communicated by {@link android.media.AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}).
Can only be used after having set a listener with {@link AudioPolicy#setAudioPolicyFocusListener(AudioPolicyFocusListener)}.
private AudioPolicyFocusListener
mFocusListener
private android.content.Context
mContext
private AudioPolicyConfig
mConfig
private final IAudioPolicyCallback
mPolicyCb
private final EventHandler
mEventHandler
private static final int
MSG_POLICY_STATUS_CHANGE
private static final int
MSG_FOCUS_GRANT
private static final int
MSG_FOCUS_LOSS
private static android.media.IAudioService
sService
Constructors Summary
private AudioPolicy(AudioPolicyConfig config, android.content.Context context, android.os.Looper looper, AudioPolicyFocusListener fl, AudioPolicyStatusListener sl)
The parameter is guaranteed non-null through the Builder

        mConfig = config;
        mStatus = POLICY_STATUS_UNREGISTERED;
        mContext = context;
        if (looper == null) {
            looper = Looper.getMainLooper();
        }
        if (looper != null) {
            mEventHandler = new EventHandler(this, looper);
        } else {
            mEventHandler = null;
            Log.e(TAG, "No event handler due to looper without a thread");
        }
        mFocusListener = fl;
        mStatusListener = sl;
    
Methods Summary
private static java.lang.StringaddressForTag(AudioMix mix)

        return "addr=" + mix.getRegistration();
    
public IAudioPolicyCallbackcb()

hide

 return mPolicyCb; 
private voidcheckMixReadyToUse(AudioMix mix, boolean forTrack)

        if (mix == null) {
            String msg = forTrack ? "Invalid null AudioMix for AudioTrack creation"
                    : "Invalid null AudioMix for AudioRecord creation";
            throw new IllegalArgumentException(msg);
        }
        if (!mConfig.mMixes.contains(mix)) {
            throw new IllegalArgumentException("Invalid mix: not part of this policy");
        }
        if ((mix.getRouteFlags() & AudioMix.ROUTE_FLAG_LOOP_BACK) != AudioMix.ROUTE_FLAG_LOOP_BACK)
        {
            throw new IllegalArgumentException("Invalid AudioMix: not defined for loop back");
        }
        if (forTrack && (mix.getMixType() != AudioMix.MIX_TYPE_RECORDERS)) {
            throw new IllegalArgumentException(
                    "Invalid AudioMix: not defined for being a recording source");
        }
        if (!forTrack && (mix.getMixType() != AudioMix.MIX_TYPE_PLAYERS)) {
            throw new IllegalArgumentException(
                    "Invalid AudioMix: not defined for capturing playback");
        }
    
public android.media.AudioRecordcreateAudioRecordSink(AudioMix mix)
Create an {@link AudioRecord} instance that is associated with the given {@link AudioMix}. Audio buffers recorded through the created instance will contain the mix of the audio streams that fed the given mixer.

param
mix a non-null {@link AudioMix} instance whose routing flags was defined with {@link AudioMix#ROUTE_FLAG_LOOP_BACK}, previously added to this policy.
return
a new {@link AudioRecord} instance whose data format is the one defined in the {@link AudioMix}, or null if this policy was not successfully registered with {@link AudioManager#registerAudioPolicy(AudioPolicy)}.
throws
IllegalArgumentException

        if (!policyReadyToUse()) {
            Log.e(TAG, "Cannot create AudioRecord sink for AudioMix");
            return null;
        }
        checkMixReadyToUse(mix, false/*not for an AudioTrack*/);
        // create an AudioFormat from the mix format compatible with recording, as the mix
        // was defined for playback
        AudioFormat mixFormat = new AudioFormat.Builder(mix.getFormat())
                .setChannelMask(AudioFormat.inChannelMaskFromOutChannelMask(
                        mix.getFormat().getChannelMask()))
                .build();
        // create the AudioRecord, configured for loop back, using the same format as the mix
        AudioRecord ar = new AudioRecord(
                new AudioAttributes.Builder()
                        .setInternalCapturePreset(MediaRecorder.AudioSource.REMOTE_SUBMIX)
                        .addTag(addressForTag(mix))
                        .build(),
                mixFormat,
                AudioRecord.getMinBufferSize(mix.getFormat().getSampleRate(),
                        // using stereo for buffer size to avoid the current poor support for masks
                        AudioFormat.CHANNEL_IN_STEREO, mix.getFormat().getEncoding()),
                AudioManager.AUDIO_SESSION_ID_GENERATE
                );
        return ar;
    
public android.media.AudioTrackcreateAudioTrackSource(AudioMix mix)
Create an {@link AudioTrack} instance that is associated with the given {@link AudioMix}. Audio buffers played through the created instance will be sent to the given mix to be recorded through the recording APIs.

param
mix a non-null {@link AudioMix} instance whose routing flags was defined with {@link AudioMix#ROUTE_FLAG_LOOP_BACK}, previously added to this policy.
return
a new {@link AudioTrack} instance whose data format is the one defined in the {@link AudioMix}, or null if this policy was not successfully registered with {@link AudioManager#registerAudioPolicy(AudioPolicy)}.
throws
IllegalArgumentException

        if (!policyReadyToUse()) {
            Log.e(TAG, "Cannot create AudioTrack source for AudioMix");
            return null;
        }
        checkMixReadyToUse(mix, true/*for an AudioTrack*/);
        // create the AudioTrack, configured for loop back, using the same format as the mix
        AudioTrack at = new AudioTrack(
                new AudioAttributes.Builder()
                        .setUsage(AudioAttributes.USAGE_VIRTUAL_SOURCE)
                        .addTag(addressForTag(mix))
                        .build(),
                mix.getFormat(),
                AudioTrack.getMinBufferSize(mix.getFormat().getSampleRate(),
                        mix.getFormat().getChannelMask(), mix.getFormat().getEncoding()),
                AudioTrack.MODE_STREAM,
                AudioManager.AUDIO_SESSION_ID_GENERATE
                );
        return at;
    
public AudioPolicyConfiggetConfig()

hide


      
        return mConfig; 
public intgetFocusDuckingBehavior()
Returns the current behavior for audio focus-related ducking.

return
{@link #FOCUS_POLICY_DUCKING_IN_APP} or {@link #FOCUS_POLICY_DUCKING_IN_POLICY}

        return mConfig.mDuckingPolicy;
    
private static android.media.IAudioServicegetService()

        if (sService != null) {
            return sService;
        }
        IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
        sService = IAudioService.Stub.asInterface(b);
        return sService;
    
public intgetStatus()

        return mStatus;
    
public booleanhasFocusListener()

hide

 return mFocusListener != null; 
private voidonPolicyStatusChange()

        AudioPolicyStatusListener l;
        synchronized (mLock) {
            if (mStatusListener == null) {
                return;
            }
            l = mStatusListener;
        }
        l.onStatusChange();
    
private booleanpolicyReadyToUse()

        synchronized (mLock) {
            if (mStatus != POLICY_STATUS_REGISTERED) {
                Log.e(TAG, "Cannot use unregistered AudioPolicy");
                return false;
            }
            if (mContext == null) {
                Log.e(TAG, "Cannot use AudioPolicy without context");
                return false;
            }
            if (mRegistrationId == null) {
                Log.e(TAG, "Cannot use unregistered AudioPolicy");
                return false;
            }
        }
        if (!(PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
                        android.Manifest.permission.MODIFY_AUDIO_ROUTING))) {
            Slog.w(TAG, "Cannot use AudioPolicy for pid " + Binder.getCallingPid() + " / uid "
                    + Binder.getCallingUid() + ", needs MODIFY_AUDIO_ROUTING");
            return false;
        }
        return true;
    
private voidsendMsg(int msg)

        if (mEventHandler != null) {
            mEventHandler.sendEmptyMessage(msg);
        }
    
private voidsendMsg(int msg, java.lang.Object obj, int i)

        if (mEventHandler != null) {
            mEventHandler.sendMessage(
                    mEventHandler.obtainMessage(msg, i /*arg1*/, 0 /*arg2, ignored*/, obj));
        }
    
public intsetFocusDuckingBehavior(int behavior)
Sets the behavior for audio focus-related ducking. There must be a focus listener if this policy is to handle ducking.

param
behavior {@link #FOCUS_POLICY_DUCKING_IN_APP} or {@link #FOCUS_POLICY_DUCKING_IN_POLICY}
return
{@link AudioManager#SUCCESS} or {@link AudioManager#ERROR} (for instance if there is already an audio policy that handles ducking).
throws
IllegalArgumentException
throws
IllegalStateException

        if ((behavior != FOCUS_POLICY_DUCKING_IN_APP)
                && (behavior != FOCUS_POLICY_DUCKING_IN_POLICY)) {
            throw new IllegalArgumentException("Invalid ducking behavior " + behavior);
        }
        synchronized (mLock) {
            if (mStatus != POLICY_STATUS_REGISTERED) {
                throw new IllegalStateException(
                        "Cannot change ducking behavior for unregistered policy");
            }
            if ((behavior == FOCUS_POLICY_DUCKING_IN_POLICY)
                    && (mFocusListener == null)) {
                // there must be a focus listener if the policy handles ducking
                throw new IllegalStateException(
                        "Cannot handle ducking without an audio focus listener");
            }
            IAudioService service = getService();
            try {
                final int status = service.setFocusPropertiesForPolicy(behavior /*duckingBehavior*/,
                        this.cb());
                if (status == AudioManager.SUCCESS) {
                    mConfig.mDuckingPolicy = behavior;
                }
                return status;
            } catch (RemoteException e) {
                Log.e(TAG, "Dead object in setFocusPropertiesForPolicy for behavior", e);
                return AudioManager.ERROR;
            }
        }
    
public voidsetRegistration(java.lang.String regId)

        synchronized (mLock) {
            mRegistrationId = regId;
            mConfig.setRegistration(regId);
            if (regId != null) {
                mStatus = POLICY_STATUS_REGISTERED;
            } else {
                mStatus = POLICY_STATUS_UNREGISTERED;
            }
        }
        sendMsg(MSG_POLICY_STATUS_CHANGE);
    
public java.lang.StringtoLogFriendlyString()

        String textDump = new String("android.media.audiopolicy.AudioPolicy:\n");
        textDump += "config=" + mConfig.toLogFriendlyString();
        return (textDump);