FileDocCategorySizeDatePackage
AudioService.javaAPI DocAndroid 5.1 API259708Thu Mar 12 22:22:30 GMT 2015android.media

AudioService

public class AudioService extends IAudioService.Stub
The implementation of the volume manager service.

This implementation focuses on delivering a responsive UI. Most methods are asynchronous to external calls. For example, the task of setting a volume will update our internal state, but in a separate thread will set the system volume and later persist to the database. Similarly, setting the ringer mode will update the state and broadcast a change and in a separate thread later persist the ringer mode.

hide

Fields Summary
private static final String
TAG
protected static final boolean
DEBUG_MODE
Debug audio mode
protected static final boolean
DEBUG_AP
Debug audio policy feature
protected static final boolean
DEBUG_VOL
Debug volumes
private static final boolean
DEBUG_SESSIONS
debug calls to media session apis
private static final boolean
VOLUME_SETS_RINGER_MODE_SILENT
Allow volume changes to set ringer mode to silent?
private static final boolean
PREVENT_VOLUME_ADJUSTMENT_IF_SILENT
In silent mode, are volume adjustments (raises) prevented?
private static final int
PERSIST_DELAY
How long to delay before persisting a change in volume/ringer mode.
public static final int
PLAY_SOUND_DELAY
The delay before playing a sound. This small period exists so the user can press another key (non-volume keys, too) to have it NOT be audible.

PhoneWindow will implement this part.

private static final int
FLAG_ADJUST_VOLUME
Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
private final android.content.Context
mContext
private final android.content.ContentResolver
mContentResolver
private final android.app.AppOpsManager
mAppOps
private static final int
PLATFORM_DEFAULT
private static final int
PLATFORM_VOICE
private static final int
PLATFORM_TELEVISION
private final int
mPlatformType
private final VolumeController
mVolumeController
The controller for the volume UI.
private static final int
SENDMSG_REPLACE
If the msg is already queued, replace it with this one.
private static final int
SENDMSG_NOOP
If the msg is already queued, ignore this one and leave the old.
private static final int
SENDMSG_QUEUE
If the msg is already queued, queue this one and leave the old.
private static final int
MSG_SET_DEVICE_VOLUME
private static final int
MSG_PERSIST_VOLUME
private static final int
MSG_PERSIST_MASTER_VOLUME
private static final int
MSG_PERSIST_RINGER_MODE
private static final int
MSG_MEDIA_SERVER_DIED
private static final int
MSG_PLAY_SOUND_EFFECT
private static final int
MSG_BTA2DP_DOCK_TIMEOUT
private static final int
MSG_LOAD_SOUND_EFFECTS
private static final int
MSG_SET_FORCE_USE
private static final int
MSG_BT_HEADSET_CNCT_FAILED
private static final int
MSG_SET_ALL_VOLUMES
private static final int
MSG_PERSIST_MASTER_VOLUME_MUTE
private static final int
MSG_REPORT_NEW_ROUTES
private static final int
MSG_SET_FORCE_BT_A2DP_USE
private static final int
MSG_CHECK_MUSIC_ACTIVE
private static final int
MSG_BROADCAST_AUDIO_BECOMING_NOISY
private static final int
MSG_CONFIGURE_SAFE_MEDIA_VOLUME
private static final int
MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED
private static final int
MSG_PERSIST_SAFE_VOLUME_STATE
private static final int
MSG_BROADCAST_BT_CONNECTION_STATE
private static final int
MSG_UNLOAD_SOUND_EFFECTS
private static final int
MSG_SYSTEM_READY
private static final int
MSG_PERSIST_MUSIC_ACTIVE_MS
private static final int
MSG_PERSIST_MICROPHONE_MUTE
private static final int
MSG_SET_WIRED_DEVICE_CONNECTION_STATE
private static final int
MSG_SET_A2DP_SRC_CONNECTION_STATE
private static final int
MSG_SET_A2DP_SINK_CONNECTION_STATE
private static final int
BTA2DP_DOCK_TIMEOUT_MILLIS
private static final int
BT_HEADSET_CNCT_TIMEOUT_MS
private AudioSystemThread
mAudioSystemThread
private AudioHandler
mAudioHandler
private VolumeStreamState[]
mStreamStates
private SettingsObserver
mSettingsObserver
private int
mMode
private final Object
mSettingsLock
private SoundPool
mSoundPool
private final Object
mSoundEffectsLock
private static final int
NUM_SOUNDPOOL_CHANNELS
private static final int
MAX_MASTER_VOLUME
private static final int
MAX_BATCH_VOLUME_ADJUST_STEPS
private static final String
SOUND_EFFECTS_PATH
private static final List
SOUND_EFFECT_FILES
private final int[]
SOUND_EFFECT_FILES_MAP
private static int[]
MAX_STREAM_VOLUME
private static int[]
DEFAULT_STREAM_VOLUME
private final int[]
STREAM_VOLUME_ALIAS_VOICE
private final int[]
STREAM_VOLUME_ALIAS_TELEVISION
private final int[]
STREAM_VOLUME_ALIAS_DEFAULT
private int[]
mStreamVolumeAlias
private static final int[]
STEAM_VOLUME_OPS
Map AudioSystem.STREAM_* constants to app ops. This should be used after mapping through mStreamVolumeAlias.
private final boolean
mUseFixedVolume
private static final String[]
STREAM_NAMES
private final AudioSystem.ErrorCallback
mAudioSystemCallback
private int
mRingerMode
Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL}, {@link AudioManager#RINGER_MODE_SILENT}, or {@link AudioManager#RINGER_MODE_VIBRATE}.
private int
mRingerModeExternal
private int
mRingerModeAffectedStreams
private int
mRingerModeMutedStreams
private int
mMuteAffectedStreams
private int
mVibrateSetting
NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated. mVibrateSetting is just maintained during deprecation period but vibration policy is now only controlled by mHasVibrator and mRingerMode
private final boolean
mHasVibrator
private final android.content.BroadcastReceiver
mReceiver
private final HashMap
mConnectedDevices
private int
mForcedUseForComm
private final boolean
mUseMasterVolume
private final int[]
mMasterVolumeRamp
private final ArrayList
mSetModeDeathHandlers
private final ArrayList
mScoClients
private android.bluetooth.BluetoothHeadset
mBluetoothHeadset
private android.bluetooth.BluetoothDevice
mBluetoothHeadsetDevice
private int
mScoAudioState
private static final int
SCO_STATE_INACTIVE
private static final int
SCO_STATE_ACTIVATE_REQ
private static final int
SCO_STATE_ACTIVE_INTERNAL
private static final int
SCO_STATE_DEACTIVATE_REQ
private static final int
SCO_STATE_ACTIVE_EXTERNAL
private static final int
SCO_STATE_DEACTIVATE_EXT_REQ
private int
mScoAudioMode
private static final int
SCO_MODE_UNDEFINED
private static final int
SCO_MODE_VIRTUAL_CALL
private static final int
SCO_MODE_RAW
private static final int
SCO_MODE_VR
private static final int
SCO_MODE_MAX
private int
mScoConnectionState
private boolean
mSystemReady
private SoundPoolCallback
mSoundPoolCallBack
private SoundPoolListenerThread
mSoundPoolListenerThread
private android.os.Looper
mSoundPoolLooper
private static int
sSoundEffectVolumeDb
private int
mPrevVolDirection
private android.app.KeyguardManager
mKeyguardManager
private int
mVolumeControlStream
private final Object
mForceControlStreamLock
private ForceControlStreamClient
mForceControlStreamClient
private volatile IRingtonePlayer
mRingtonePlayer
private int
mDeviceOrientation
private int
mDeviceRotation
private boolean
mBluetoothA2dpEnabled
private final Object
mBluetoothA2dpEnabledLock
final AudioRoutesInfo
mCurAudioRoutes
final android.os.RemoteCallbackList
mRoutesObservers
int
mFixedVolumeDevices
int
mFullVolumeDevices
private final boolean
mMonitorOrientation
private final boolean
mMonitorRotation
private boolean
mDockAudioMediaEnabled
private int
mDockState
private StreamVolumeCommand
mPendingVolumeCommand
private PowerManager.WakeLock
mAudioEventWakeLock
private final MediaFocusControl
mMediaFocusControl
private android.bluetooth.BluetoothA2dp
mA2dp
private final Object
mA2dpAvrcpLock
private boolean
mAvrcpAbsVolSupported
private AudioOrientationEventListener
mOrientationListener
private static Long
mLastDeviceConnectMsgTime
private AudioManagerInternal.RingerModeDelegate
mRingerModeDelegate
private int
mRmtSbmxFullVolRefCount
private ArrayList
mRmtSbmxFullVolDeathHandlers
private static final String
TAG_AUDIO_ASSETS
private static final String
ATTR_VERSION
private static final String
TAG_GROUP
private static final String
ATTR_GROUP_NAME
private static final String
TAG_ASSET
private static final String
ATTR_ASSET_ID
private static final String
ATTR_ASSET_FILE
private static final String
ASSET_FILE_VERSION
private static final String
GROUP_TOUCH_SOUNDS
private static final int
SOUND_EFFECTS_LOAD_TIMEOUT_MS
private BluetoothProfile.ServiceListener
mBluetoothProfileServiceListener
int
mBecomingNoisyIntentDevices
private String
mDockAddress
private static final int
SAFE_MEDIA_VOLUME_NOT_CONFIGURED
private static final int
SAFE_MEDIA_VOLUME_DISABLED
private static final int
SAFE_MEDIA_VOLUME_INACTIVE
private static final int
SAFE_MEDIA_VOLUME_ACTIVE
private Integer
mSafeMediaVolumeState
private int
mMcc
private int
mSafeMediaVolumeIndex
private final int
mSafeMediaVolumeDevices
private int
mMusicActiveMs
private static final int
UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX
private static final int
MUSIC_ACTIVE_POLL_PERIOD_MS
private static final int
SAFE_VOLUME_CONFIGURE_TIMEOUT_MS
private boolean
mHdmiSystemAudioSupported
private android.hardware.hdmi.HdmiTvClient
mHdmiTvClient
private android.hardware.hdmi.HdmiControlManager
mHdmiManager
private android.hardware.hdmi.HdmiPlaybackClient
mHdmiPlaybackClient
private boolean
mHdmiCecSink
private MyDisplayStatusCallback
mHdmiDisplayStatusCallback
private Boolean
mCameraSoundForced
private static final String[]
RINGER_MODE_NAMES
private HashMap
mAudioPolicies
private int
mAudioPolicyCounter
Constructors Summary
public AudioService(android.content.Context context)

hide


    ///////////////////////////////////////////////////////////////////////////
    // Construction
    ///////////////////////////////////////////////////////////////////////////

      
       
        mContext = context;
        mContentResolver = context.getContentResolver();
        mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);

        if (mContext.getResources().getBoolean(
                com.android.internal.R.bool.config_voice_capable)) {
            mPlatformType = PLATFORM_VOICE;
        } else if (context.getPackageManager().hasSystemFeature(
                                                            PackageManager.FEATURE_LEANBACK)) {
            mPlatformType = PLATFORM_TELEVISION;
        } else {
            mPlatformType = PLATFORM_DEFAULT;
        }

        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
        mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");

        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
        mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();

       // Intialized volume
        int maxVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps",
                MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
        if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
            MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxVolume;
            DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4;
        }
        maxVolume = SystemProperties.getInt("ro.config.media_vol_steps",
                MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
        if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
            MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume;
            DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
        }

        sSoundEffectVolumeDb = context.getResources().getInteger(
                com.android.internal.R.integer.config_soundEffectVolumeDb);

        mForcedUseForComm = AudioSystem.FORCE_NONE;

        createAudioSystemThread();

        mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
                mContext, mVolumeController, this);

        AudioSystem.setErrorCallback(mAudioSystemCallback);

        boolean cameraSoundForced = mContext.getResources().getBoolean(
                com.android.internal.R.bool.config_camera_sound_forced);
        mCameraSoundForced = new Boolean(cameraSoundForced);
        sendMsg(mAudioHandler,
                MSG_SET_FORCE_USE,
                SENDMSG_QUEUE,
                AudioSystem.FOR_SYSTEM,
                cameraSoundForced ?
                        AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
                null,
                0);

        mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
                                                        Settings.Global.AUDIO_SAFE_VOLUME_STATE,
                                                        SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
        // The default safe volume index read here will be replaced by the actual value when
        // the mcc is read by onConfigureSafeVolume()
        mSafeMediaVolumeIndex = mContext.getResources().getInteger(
                com.android.internal.R.integer.config_safe_media_volume_index) * 10;

        mUseFixedVolume = mContext.getResources().getBoolean(
                com.android.internal.R.bool.config_useFixedVolume);
        mUseMasterVolume = context.getResources().getBoolean(
                com.android.internal.R.bool.config_useMasterVolume);
        mMasterVolumeRamp = context.getResources().getIntArray(
                com.android.internal.R.array.config_masterVolumeRamp);

        // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
        // array initialized by updateStreamVolumeAlias()
        updateStreamVolumeAlias(false /*updateVolumes*/);
        readPersistedSettings();
        mSettingsObserver = new SettingsObserver();
        createStreamStates();

        readAndSetLowRamDevice();

        // Call setRingerModeInt() to apply correct mute
        // state on streams affected by ringer mode.
        mRingerModeMutedStreams = 0;
        setRingerModeInt(getRingerModeInternal(), false);

        // Register for device connection intent broadcasts.
        IntentFilter intentFilter =
                new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
        intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
        intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
        intentFilter.addAction(AudioManager.ACTION_USB_AUDIO_ACCESSORY_PLUG);
        intentFilter.addAction(AudioManager.ACTION_USB_AUDIO_DEVICE_PLUG);
        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
        intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);

        intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
        // TODO merge orientation and rotation
        mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
        if (mMonitorOrientation) {
            Log.v(TAG, "monitoring device orientation");
            // initialize orientation in AudioSystem
            setOrientationForAudioSystem();
        }
        mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
        if (mMonitorRotation) {
            mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
                    .getDefaultDisplay().getRotation();
            Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);

            mOrientationListener = new AudioOrientationEventListener(mContext);
            mOrientationListener.enable();

            // initialize rotation in AudioSystem
            setRotationForAudioSystem();
        }

        context.registerReceiver(mReceiver, intentFilter);

        restoreMasterVolume();

        LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
    
Methods Summary
public intabandonAudioFocus(IAudioFocusDispatcher fd, java.lang.String clientId, AudioAttributes aa)

        return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
    
public voidadjustMasterVolume(int steps, int flags, java.lang.String callingPackage)

see
AudioManager#adjustMasterVolume(int, int)

        adjustMasterVolume(steps, flags, callingPackage, Binder.getCallingUid());
    
public voidadjustMasterVolume(int steps, int flags, java.lang.String callingPackage, int uid)

        if (mUseFixedVolume) {
            return;
        }
        ensureValidSteps(steps);
        int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
        int delta = 0;
        int numSteps = Math.abs(steps);
        int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
        for (int i = 0; i < numSteps; ++i) {
            delta = findVolumeDelta(direction, volume);
            volume += delta;
        }

        //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
        setMasterVolume(volume, flags, callingPackage, uid);
    
public voidadjustStreamVolume(int streamType, int direction, int flags, java.lang.String callingPackage)

see
AudioManager#adjustStreamVolume(int, int, int)

        adjustStreamVolume(streamType, direction, flags, callingPackage, Binder.getCallingUid());
    
private voidadjustStreamVolume(int streamType, int direction, int flags, java.lang.String callingPackage, int uid)

        if (mUseFixedVolume) {
            return;
        }
        if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction
                + ", flags="+flags);

        ensureValidDirection(direction);
        ensureValidStreamType(streamType);

        // use stream type alias here so that streams with same alias have the same behavior,
        // including with regard to silent mode control (e.g the use of STREAM_RING below and in
        // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
        int streamTypeAlias = mStreamVolumeAlias[streamType];
        VolumeStreamState streamState = mStreamStates[streamTypeAlias];

        final int device = getDeviceForStream(streamTypeAlias);

        int aliasIndex = streamState.getIndex(device);
        boolean adjustVolume = true;
        int step;

        // skip a2dp absolute volume control request when the device
        // is not an a2dp device
        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
            return;
        }

        if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
                != AppOpsManager.MODE_ALLOWED) {
            return;
        }

        // reset any pending volume command
        synchronized (mSafeMediaVolumeState) {
            mPendingVolumeCommand = null;
        }

        flags &= ~AudioManager.FLAG_FIXED_VOLUME;
        if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
               ((device & mFixedVolumeDevices) != 0)) {
            flags |= AudioManager.FLAG_FIXED_VOLUME;

            // Always toggle between max safe volume and 0 for fixed volume devices where safe
            // volume is enforced, and max and 0 for the others.
            // This is simulated by stepping by the full allowed volume range
            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
                    (device & mSafeMediaVolumeDevices) != 0) {
                step = mSafeMediaVolumeIndex;
            } else {
                step = streamState.getMaxIndex();
            }
            if (aliasIndex != 0) {
                aliasIndex = step;
            }
        } else {
            // convert one UI step (+/-1) into a number of internal units on the stream alias
            step = rescaleIndex(10, streamType, streamTypeAlias);
        }

        // If either the client forces allowing ringer modes for this adjustment,
        // or the stream type is one that is affected by ringer modes
        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
                (streamTypeAlias == getMasterStreamType())) {
            int ringerMode = getRingerModeInternal();
            // do not vibrate if already in vibrate mode
            if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
                flags &= ~AudioManager.FLAG_VIBRATE;
            }
            // Check if the ringer mode changes with this volume adjustment. If
            // it does, it will handle adjusting the volume, so we won't below
            final int result = checkForRingerModeChange(aliasIndex, direction, step);
            adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
            // If suppressing a volume adjustment in silent mode, display the UI hint
            if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
                flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
            }
            // If suppressing a volume down adjustment in vibrate mode, display the UI hint
            if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
                flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
            }
        }

        int oldIndex = mStreamStates[streamType].getIndex(device);

        if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {

            // Check if volume update should be send to AVRCP
            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
                synchronized (mA2dpAvrcpLock) {
                    if (mA2dp != null && mAvrcpAbsVolSupported) {
                        mA2dp.adjustAvrcpAbsoluteVolume(direction);
                    }
                }
            }

            if ((direction == AudioManager.ADJUST_RAISE) &&
                    !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
                Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
                mVolumeController.postDisplaySafeVolumeWarning(flags);
            } else if (streamState.adjustIndex(direction * step, device)) {
                // Post message to set system volume (it in turn will post a message
                // to persist). Do not change volume if stream is muted.
                sendMsg(mAudioHandler,
                        MSG_SET_DEVICE_VOLUME,
                        SENDMSG_QUEUE,
                        device,
                        0,
                        streamState,
                        0);
            }

            // Check if volume update should be send to Hdmi system audio.
            int newIndex = mStreamStates[streamType].getIndex(device);
            if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
                setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
            }
            if (mHdmiManager != null) {
                synchronized (mHdmiManager) {
                    // mHdmiCecSink true => mHdmiPlaybackClient != null
                    if (mHdmiCecSink &&
                            streamTypeAlias == AudioSystem.STREAM_MUSIC &&
                            oldIndex != newIndex) {
                        synchronized (mHdmiPlaybackClient) {
                            int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
                                                               KeyEvent.KEYCODE_VOLUME_UP;
                            mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
                            mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
                        }
                    }
                }
            }
        }
        int index = mStreamStates[streamType].getIndex(device);
        sendVolumeUpdate(streamType, oldIndex, index, flags);
    
public voidadjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags, java.lang.String callingPackage)

see
AudioManager#adjustVolume(int, int)

        adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
                Binder.getCallingUid());
    
private voidadjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags, java.lang.String callingPackage, int uid)

        if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType
                + ", flags=" + flags);
        int streamType;
        if (mVolumeControlStream != -1) {
            streamType = mVolumeControlStream;
        } else {
            streamType = getActiveStreamType(suggestedStreamType);
        }
        final int resolvedStream = mStreamVolumeAlias[streamType];

        // Play sounds on STREAM_RING only.
        if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
                resolvedStream != AudioSystem.STREAM_RING) {
            flags &= ~AudioManager.FLAG_PLAY_SOUND;
        }

        // For notifications/ring, show the ui before making any adjustments
        if (mVolumeController.suppressAdjustment(resolvedStream, flags)) {
            direction = 0;
            flags &= ~AudioManager.FLAG_PLAY_SOUND;
            flags &= ~AudioManager.FLAG_VIBRATE;
            if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
        }

        adjustStreamVolume(streamType, direction, flags, callingPackage, uid);
    
public voidavrcpSupportsAbsoluteVolume(java.lang.String address, boolean support)

        // address is not used for now, but may be used when multiple a2dp devices are supported
        synchronized (mA2dpAvrcpLock) {
            mAvrcpAbsVolSupported = support;
            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
                    mStreamStates[AudioSystem.STREAM_MUSIC], 0);
            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
                    mStreamStates[AudioSystem.STREAM_RING], 0);
        }
    
private voidbroadcastMasterMuteStatus(boolean muted)

        Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
        sendStickyBroadcastToAll(intent);
    
private voidbroadcastRingerMode(java.lang.String action, int ringerMode)

        // Send sticky broadcast
        Intent broadcast = new Intent(action);
        broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
        broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
        sendStickyBroadcastToAll(broadcast);
    
private voidbroadcastScoConnectionState(int state)

        sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
                SENDMSG_QUEUE, state, 0, null, 0);
    
private voidbroadcastVibrateSetting(int vibrateType)

        // Send broadcast
        if (ActivityManagerNative.isSystemReady()) {
            Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
            sendBroadcastToAll(broadcast);
        }
    
private voidcancelA2dpDeviceTimeout()

        mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
    
private voidcheckAllAliasStreamVolumes()

        synchronized (VolumeStreamState.class) {
            int numStreamTypes = AudioSystem.getNumStreamTypes();
            for (int streamType = 0; streamType < numStreamTypes; streamType++) {
                if (streamType != mStreamVolumeAlias[streamType]) {
                    mStreamStates[streamType].
                                    setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]);
                }
                // apply stream volume
                if (!mStreamStates[streamType].isMuted_syncVSS()) {
                    mStreamStates[streamType].applyAllVolumes();
                }
            }
        }
    
private voidcheckAllFixedVolumeDevices(int streamType)

        mStreamStates[streamType].checkFixedVolumeDevices();
    
private voidcheckAllFixedVolumeDevices()

        int numStreamTypes = AudioSystem.getNumStreamTypes();
        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
            mStreamStates[streamType].checkFixedVolumeDevices();
        }
    
booleancheckAudioSettingsPermission(java.lang.String method)

        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
                == PackageManager.PERMISSION_GRANTED) {
            return true;
        }
        String msg = "Audio Settings Permission Denial: " + method + " from pid="
                + Binder.getCallingPid()
                + ", uid=" + Binder.getCallingUid();
        Log.w(TAG, msg);
        return false;
    
private intcheckForRingerModeChange(int oldIndex, int direction, int step)
Checks if the adjustment should change ringer mode instead of just adjusting volume. If so, this will set the proper ringer mode and volume indices on the stream states.

        int result = FLAG_ADJUST_VOLUME;
        int ringerMode = getRingerModeInternal();

        switch (ringerMode) {
        case RINGER_MODE_NORMAL:
            if (direction == AudioManager.ADJUST_LOWER) {
                if (mHasVibrator) {
                    // "step" is the delta in internal index units corresponding to a
                    // change of 1 in UI index units.
                    // Because of rounding when rescaling from one stream index range to its alias
                    // index range, we cannot simply test oldIndex == step:
                    //   (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
                    if (step <= oldIndex && oldIndex < 2 * step) {
                        ringerMode = RINGER_MODE_VIBRATE;
                    }
                } else {
                    // (oldIndex < step) is equivalent to (old UI index == 0)
                    if ((oldIndex < step)
                            && VOLUME_SETS_RINGER_MODE_SILENT
                            && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
                        ringerMode = RINGER_MODE_SILENT;
                    }
                }
            }
            break;
        case RINGER_MODE_VIBRATE:
            if (!mHasVibrator) {
                Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
                        "but no vibrator is present");
                break;
            }
            if ((direction == AudioManager.ADJUST_LOWER)) {
                if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
                    if (VOLUME_SETS_RINGER_MODE_SILENT) {
                        ringerMode = RINGER_MODE_SILENT;
                    } else {
                        result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
                    }
                }
            } else if (direction == AudioManager.ADJUST_RAISE) {
                ringerMode = RINGER_MODE_NORMAL;
            }
            result &= ~FLAG_ADJUST_VOLUME;
            break;
        case RINGER_MODE_SILENT:
            if (direction == AudioManager.ADJUST_RAISE) {
                if (PREVENT_VOLUME_ADJUSTMENT_IF_SILENT) {
                    result |= AudioManager.FLAG_SHOW_SILENT_HINT;
                } else {
                  if (mHasVibrator) {
                      ringerMode = RINGER_MODE_VIBRATE;
                  } else {
                      ringerMode = RINGER_MODE_NORMAL;
                  }
                }
            }
            result &= ~FLAG_ADJUST_VOLUME;
            break;
        default:
            Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
            break;
        }

        setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);

        mPrevVolDirection = direction;

        return result;
    
private booleancheckSafeMediaVolume(int streamType, int index, int device)

        synchronized (mSafeMediaVolumeState) {
            if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
                    (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
                    ((device & mSafeMediaVolumeDevices) != 0) &&
                    (index > mSafeMediaVolumeIndex)) {
                return false;
            }
            return true;
        }
    
private voidcheckScoAudioState()

        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
                mScoAudioState == SCO_STATE_INACTIVE &&
                mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
                != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
        }
    
private intcheckSendBecomingNoisyIntent(int device, int state)


    // must be called before removing the device from mConnectedDevices
          
        int delay = 0;
        if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
            int devices = 0;
            for (int dev : mConnectedDevices.keySet()) {
                if (((dev & AudioSystem.DEVICE_BIT_IN) == 0) &&
                        ((dev & mBecomingNoisyIntentDevices) != 0)) {
                   devices |= dev;
                }
            }
            if (devices == device) {
                sendMsg(mAudioHandler,
                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
                        SENDMSG_REPLACE,
                        0,
                        0,
                        null,
                        0);
                delay = 1000;
            }
        }

        if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
                mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
                mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
            synchronized (mLastDeviceConnectMsgTime) {
                long time = SystemClock.uptimeMillis();
                if (mLastDeviceConnectMsgTime > time) {
                    delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
                }
            }
        }
        return delay;
    
public voidclearAllScoClients(int exceptPid, boolean stopSco)

        synchronized(mScoClients) {
            ScoClient savedClient = null;
            int size = mScoClients.size();
            for (int i = 0; i < size; i++) {
                ScoClient cl = mScoClients.get(i);
                if (cl.getPid() != exceptPid) {
                    cl.clearCount(stopSco);
                } else {
                    savedClient = cl;
                }
            }
            mScoClients.clear();
            if (savedClient != null) {
                mScoClients.add(savedClient);
            }
        }
    
private voidconfigureHdmiPlugIntent(android.content.Intent intent, int state)

        intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
        intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
        if (state == 1) {
            ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
            int[] portGeneration = new int[1];
            int status = AudioSystem.listAudioPorts(ports, portGeneration);
            if (status == AudioManager.SUCCESS) {
                for (AudioPort port : ports) {
                    if (port instanceof AudioDevicePort) {
                        final AudioDevicePort devicePort = (AudioDevicePort) port;
                        if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
                                devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
                            // format the list of supported encodings
                            int[] formats = devicePort.formats();
                            if (formats.length > 0) {
                                ArrayList<Integer> encodingList = new ArrayList(1);
                                for (int format : formats) {
                                    // a format in the list can be 0, skip it
                                    if (format != AudioFormat.ENCODING_INVALID) {
                                        encodingList.add(format);
                                    }
                                }
                                int[] encodingArray = new int[encodingList.size()];
                                for (int i = 0 ; i < encodingArray.length ; i++) {
                                    encodingArray[i] = encodingList.get(i);
                                }
                                intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
                            }
                            // find the maximum supported number of channels
                            int maxChannels = 0;
                            for (int mask : devicePort.channelMasks()) {
                                int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
                                if (channelCount > maxChannels) {
                                    maxChannels = channelCount;
                                }
                            }
                            intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
                        }
                    }
                }
            }
        }
    
private voidcreateAudioSystemThread()

        mAudioSystemThread = new AudioSystemThread();
        mAudioSystemThread.start();
        waitForAudioHandlerCreation();
    
private voidcreateStreamStates()

        int numStreamTypes = AudioSystem.getNumStreamTypes();
        VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];

        for (int i = 0; i < numStreamTypes; i++) {
            streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
        }

        checkAllFixedVolumeDevices();
        checkAllAliasStreamVolumes();
    
public voiddisableSafeMediaVolume()

        enforceSelfOrSystemUI("disable the safe media volume");
        synchronized (mSafeMediaVolumeState) {
            setSafeMediaVolumeEnabled(false);
            if (mPendingVolumeCommand != null) {
                onSetStreamVolume(mPendingVolumeCommand.mStreamType,
                                  mPendingVolumeCommand.mIndex,
                                  mPendingVolumeCommand.mFlags,
                                  mPendingVolumeCommand.mDevice);
                mPendingVolumeCommand = null;
            }
        }
    
private booleandiscardRmtSbmxFullVolDeathHandlerFor(android.os.IBinder cb)
call must be synchronized on mRmtSbmxFullVolDeathHandlers

return
true if there is a registered death handler, false otherwise

        Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
        while (it.hasNext()) {
            final RmtSbmxFullVolDeathHandler handler = it.next();
            if (handler.isHandlerFor(cb)) {
                handler.forget();
                mRmtSbmxFullVolDeathHandlers.remove(handler);
                return true;
            }
        }
        return false;
    
private voiddisconnectBluetoothSco(int exceptPid)

        synchronized(mScoClients) {
            checkScoAudioState();
            if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
                    mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
                if (mBluetoothHeadsetDevice != null) {
                    if (mBluetoothHeadset != null) {
                        if (!mBluetoothHeadset.stopVoiceRecognition(
                                mBluetoothHeadsetDevice)) {
                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
                                    SENDMSG_REPLACE, 0, 0, null, 0);
                        }
                    } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
                            getBluetoothHeadset()) {
                        mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
                    }
                }
            } else {
                clearAllScoClients(exceptPid, true);
            }
        }
    
private voiddoSetMasterVolume(float volume, int flags)

        // don't allow changing master volume when muted
        if (!AudioSystem.getMasterMute()) {
            int oldVolume = getMasterVolume();
            AudioSystem.setMasterVolume(volume);

            int newVolume = getMasterVolume();
            if (newVolume != oldVolume) {
                // Post a persist master volume msg
                sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
                        Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
                setSystemAudioVolume(oldVolume, newVolume, getMasterMaxVolume(), flags);
            }
            // Send the volume update regardless whether there was a change.
            sendMasterVolumeUpdate(flags, oldVolume, newVolume);
        }
    
protected voiddump(java.io.FileDescriptor fd, java.io.PrintWriter pw, java.lang.String[] args)

        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);

        mMediaFocusControl.dump(pw);
        dumpStreamStates(pw);
        dumpRingerMode(pw);
        pw.println("\nAudio routes:");
        pw.print("  mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
        pw.print("  mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);

        pw.println("\nOther state:");
        pw.print("  mVolumeController="); pw.println(mVolumeController);
        pw.print("  mSafeMediaVolumeState=");
        pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
        pw.print("  mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
        pw.print("  mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
        pw.print("  mMusicActiveMs="); pw.println(mMusicActiveMs);
        pw.print("  mMcc="); pw.println(mMcc);
        pw.print("  mHasVibrator="); pw.println(mHasVibrator);

        dumpAudioPolicies(pw);
    
private voiddumpAudioPolicies(java.io.PrintWriter pw)

        pw.println("\nAudio policies:");
        synchronized (mAudioPolicies) {
            for(AudioPolicyProxy policy : mAudioPolicies.values()) {
                pw.println(policy.toLogFriendlyString());
            }
        }
    
private voiddumpRingerMode(java.io.PrintWriter pw)


        
        pw.println("\nRinger mode: ");
        pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
        pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
        pw.print("- ringer mode affected streams = 0x");
        pw.println(Integer.toHexString(mRingerModeAffectedStreams));
        pw.print("- ringer mode muted streams = 0x");
        pw.println(Integer.toHexString(mRingerModeMutedStreams));
        pw.print("- delegate = "); pw.println(mRingerModeDelegate);
    
private voiddumpStreamStates(java.io.PrintWriter pw)

        pw.println("\nStream volumes (device: index)");
        int numStreamTypes = AudioSystem.getNumStreamTypes();
        for (int i = 0; i < numStreamTypes; i++) {
            pw.println("- "+STREAM_NAMES[i]+":");
            mStreamStates[i].dump(pw);
            pw.println("");
        }
        pw.print("\n- mute affected streams = 0x");
        pw.println(Integer.toHexString(mMuteAffectedStreams));
    
private voidenforceSafeMediaVolume()

        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
        int devices = mSafeMediaVolumeDevices;
        int i = 0;

        while (devices != 0) {
            int device = 1 << i++;
            if ((device & devices) == 0) {
                continue;
            }
            int index = streamState.getIndex(device);
            if (index > mSafeMediaVolumeIndex) {
                streamState.setIndex(mSafeMediaVolumeIndex, device);
                sendMsg(mAudioHandler,
                        MSG_SET_DEVICE_VOLUME,
                        SENDMSG_QUEUE,
                        device,
                        0,
                        streamState,
                        0);
            }
            devices &= ~device;
        }
    
private voidenforceSelfOrSystemUI(java.lang.String action)

        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
                "Only SystemUI can " + action);
    
private voidensureValidDirection(int direction)

        if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) {
            throw new IllegalArgumentException("Bad direction " + direction);
        }
    
private voidensureValidRingerMode(int ringerMode)

        if (!isValidRingerMode(ringerMode)) {
            throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
        }
    
private voidensureValidSteps(int steps)

        if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
            throw new IllegalArgumentException("Bad volume adjust steps " + steps);
        }
    
private voidensureValidStreamType(int streamType)

        if (streamType < 0 || streamType >= mStreamStates.length) {
            throw new IllegalArgumentException("Bad stream type " + streamType);
        }
    
private intfindVolumeDelta(int direction, int volume)

        int delta = 0;
        if (direction == AudioManager.ADJUST_RAISE) {
            if (volume == MAX_MASTER_VOLUME) {
                return 0;
            }
            // This is the default value if we make it to the end
            delta = mMasterVolumeRamp[1];
            // If we're raising the volume move down the ramp array until we
            // find the volume we're above and use that groups delta.
            for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
                if (volume >= mMasterVolumeRamp[i - 1]) {
                    delta = mMasterVolumeRamp[i];
                    break;
                }
            }
        } else if (direction == AudioManager.ADJUST_LOWER){
            if (volume == 0) {
                return 0;
            }
            int length = mMasterVolumeRamp.length;
            // This is the default value if we make it to the end
            delta = -mMasterVolumeRamp[length - 1];
            // If we're lowering the volume move up the ramp array until we
            // find the volume we're below and use the group below it's delta
            for (int i = 2; i < length; i += 2) {
                if (volume <= mMasterVolumeRamp[i]) {
                    delta = -mMasterVolumeRamp[i - 1];
                    break;
                }
            }
        }
        return delta;
    
public voidforceRemoteSubmixFullVolume(boolean startForcing, android.os.IBinder cb)


          
        if (cb == null) {
            return;
        }
        if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
                        android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
            Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
            return;
        }
        synchronized(mRmtSbmxFullVolDeathHandlers) {
            boolean applyRequired = false;
            if (startForcing) {
                if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
                    mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
                    if (mRmtSbmxFullVolRefCount == 0) {
                        mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
                        mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
                        applyRequired = true;
                    }
                    mRmtSbmxFullVolRefCount++;
                }
            } else {
                if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
                    mRmtSbmxFullVolRefCount--;
                    if (mRmtSbmxFullVolRefCount == 0) {
                        mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
                        mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
                        applyRequired = true;
                    }
                }
            }
            if (applyRequired) {
                // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
                checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
                mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
            }
        }
    
public voidforceVolumeControlStream(int streamType, android.os.IBinder cb)

see
AudioManager#forceVolumeControlStream(int)

        synchronized(mForceControlStreamLock) {
            mVolumeControlStream = streamType;
            if (mVolumeControlStream == -1) {
                if (mForceControlStreamClient != null) {
                    mForceControlStreamClient.release();
                    mForceControlStreamClient = null;
                }
            } else {
                mForceControlStreamClient = new ForceControlStreamClient(cb);
            }
        }
    
private intgetActiveStreamType(int suggestedStreamType)

        switch (mPlatformType) {
        case PLATFORM_VOICE:
            if (isInCommunication()) {
                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
                        == AudioSystem.FORCE_BT_SCO) {
                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
                    return AudioSystem.STREAM_BLUETOOTH_SCO;
                } else {
                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
                    return AudioSystem.STREAM_VOICE_CALL;
                }
            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
                if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
                    if (DEBUG_VOL)
                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
                    return AudioSystem.STREAM_MUSIC;
                    } else {
                        if (DEBUG_VOL)
                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
                        return AudioSystem.STREAM_RING;
                }
            } else if (isAfMusicActiveRecently(0)) {
                if (DEBUG_VOL)
                    Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
                return AudioSystem.STREAM_MUSIC;
            }
            break;
        case PLATFORM_TELEVISION:
            if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
                    // TV always defaults to STREAM_MUSIC
                    return AudioSystem.STREAM_MUSIC;
            }
            break;
        default:
            if (isInCommunication()) {
                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
                        == AudioSystem.FORCE_BT_SCO) {
                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
                    return AudioSystem.STREAM_BLUETOOTH_SCO;
                } else {
                    if (DEBUG_VOL)  Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
                    return AudioSystem.STREAM_VOICE_CALL;
                }
            } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
                    StreamOverride.sDelayMs) ||
                    AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
                            StreamOverride.sDelayMs)) {
                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
                return AudioSystem.STREAM_NOTIFICATION;
            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
                if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
                    return AudioSystem.STREAM_MUSIC;
                } else {
                    if (DEBUG_VOL) Log.v(TAG,
                            "getActiveStreamType: using STREAM_NOTIFICATION as default");
                    return AudioSystem.STREAM_NOTIFICATION;
                }
            }
            break;
        }
        if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
                + suggestedStreamType);
        return suggestedStreamType;
    
private booleangetBluetoothHeadset()

        boolean result = false;
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        if (adapter != null) {
            result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
                                    BluetoothProfile.HEADSET);
        }
        // If we could not get a bluetooth headset proxy, send a failure message
        // without delay to reset the SCO audio state and clear SCO clients.
        // If we could get a proxy, send a delayed failure message that will reset our state
        // in case we don't receive onServiceConnected().
        sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
                SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
        return result;
    
public intgetCurrentAudioFocus()

        return mMediaFocusControl.getCurrentAudioFocus();
    
public static intgetDefaultStreamVolume(int streamType)

        return DEFAULT_STREAM_VOLUME[streamType];
    
private intgetDeviceForStream(int stream)

        int device = AudioSystem.getDevicesForStream(stream);
        if ((device & (device - 1)) != 0) {
            // Multiple device selection is either:
            //  - speaker + one other device: give priority to speaker in this case.
            //  - one A2DP device + another device: happens with duplicated output. In this case
            // retain the device on the A2DP output as the other must not correspond to an active
            // selection if not the speaker.
            //  - HDMI-CEC system audio mode only output: give priority to available item in order.
            if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
                device = AudioSystem.DEVICE_OUT_SPEAKER;
            } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
                device = AudioSystem.DEVICE_OUT_HDMI_ARC;
            } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
                device = AudioSystem.DEVICE_OUT_SPDIF;
            } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
                device = AudioSystem.DEVICE_OUT_AUX_LINE;
            } else {
                device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
            }
        }
        return device;
    
public intgetLastAudibleMasterVolume()
Get last audible master volume before it was muted.

        return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
    
public intgetLastAudibleStreamVolume(int streamType)
Get last audible volume before stream was muted.

        ensureValidStreamType(streamType);
        int device = getDeviceForStream(streamType);
        return (mStreamStates[streamType].getIndex(device) + 5) / 10;
    
public intgetMasterMaxVolume()

        return MAX_MASTER_VOLUME;
    
public intgetMasterStreamType()

see
AudioManager#getMasterStreamType()

        return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
    
public intgetMasterVolume()

        if (isMasterMute()) return 0;
        return getLastAudibleMasterVolume();
    
protected static intgetMaxStreamVolume(int streamType)

        return MAX_STREAM_VOLUME[streamType];
    
public intgetMode()

see
AudioManager#getMode()

        return mMode;
    
public intgetRingerModeExternal()

        synchronized(mSettingsLock) {
            return mRingerModeExternal;
        }
    
public intgetRingerModeInternal()

        synchronized(mSettingsLock) {
            return mRingerMode;
        }
    
public IRingtonePlayergetRingtonePlayer()

        return mRingtonePlayer;
    
private android.media.AudioService$ScoClientgetScoClient(android.os.IBinder cb, boolean create)

        synchronized(mScoClients) {
            ScoClient client = null;
            int size = mScoClients.size();
            for (int i = 0; i < size; i++) {
                client = mScoClients.get(i);
                if (client.getBinder() == cb)
                    return client;
            }
            if (create) {
                client = new ScoClient(cb);
                mScoClients.add(client);
            }
            return client;
        }
    
public intgetStreamMaxVolume(int streamType)

see
AudioManager#getStreamMaxVolume(int)

        ensureValidStreamType(streamType);
        return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
    
public intgetStreamVolume(int streamType)

see
AudioManager#getStreamVolume(int)

        ensureValidStreamType(streamType);
        int device = getDeviceForStream(streamType);
        synchronized (VolumeStreamState.class) {
            int index = mStreamStates[streamType].getIndex(device);

            // by convention getStreamVolume() returns 0 when a stream is muted.
            if (mStreamStates[streamType].isMuted_syncVSS()) {
                index = 0;
            }
            if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
                    (device & mFixedVolumeDevices) != 0) {
                index = mStreamStates[streamType].getMaxIndex();
            }
            return (index + 5) / 10;
        }
    
public static intgetValueForVibrateSetting(int existingValue, int vibrateType, int vibrateSetting)

see
#setVibrateSetting(int, int)


        // First clear the existing setting. Each vibrate type has two bits in
        // the value. Note '3' is '11' in binary.
        existingValue &= ~(3 << (vibrateType * 2));

        // Set into the old value
        existingValue |= (vibrateSetting & 3) << (vibrateType * 2);

        return existingValue;
    
public intgetVibrateSetting(int vibrateType)

see
AudioManager#getVibrateSetting(int)

        if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
        return (mVibrateSetting >> (vibrateType * 2)) & 3;
    
private voidhandleConfigurationChanged(android.content.Context context)
Handles device configuration changes that may map to a change in the orientation or orientation. Monitoring orientation and rotation is optional, and is defined by the definition and value of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.

        try {
            // reading new orientation "safely" (i.e. under try catch) in case anything
            // goes wrong when obtaining resources and configuration
            Configuration config = context.getResources().getConfiguration();
            // TODO merge rotation and orientation
            if (mMonitorOrientation) {
                int newOrientation = config.orientation;
                if (newOrientation != mDeviceOrientation) {
                    mDeviceOrientation = newOrientation;
                    setOrientationForAudioSystem();
                }
            }
            sendMsg(mAudioHandler,
                    MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
                    SENDMSG_REPLACE,
                    0,
                    0,
                    null,
                    0);

            boolean cameraSoundForced = mContext.getResources().getBoolean(
                    com.android.internal.R.bool.config_camera_sound_forced);
            synchronized (mSettingsLock) {
                boolean cameraSoundForcedChanged = false;
                synchronized (mCameraSoundForced) {
                    if (cameraSoundForced != mCameraSoundForced) {
                        mCameraSoundForced = cameraSoundForced;
                        cameraSoundForcedChanged = true;
                    }
                }
                if (cameraSoundForcedChanged) {
                    if (!isPlatformTelevision()) {
                        VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
                        if (cameraSoundForced) {
                            s.setAllIndexesToMax();
                            mRingerModeAffectedStreams &=
                                    ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
                        } else {
                            s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
                            mRingerModeAffectedStreams |=
                                    (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
                        }
                        // take new state into account for streams muted by ringer mode
                        setRingerModeInt(getRingerModeInternal(), false);
                    }

                    sendMsg(mAudioHandler,
                            MSG_SET_FORCE_USE,
                            SENDMSG_QUEUE,
                            AudioSystem.FOR_SYSTEM,
                            cameraSoundForced ?
                                    AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
                            null,
                            0);

                    sendMsg(mAudioHandler,
                            MSG_SET_ALL_VOLUMES,
                            SENDMSG_QUEUE,
                            0,
                            0,
                            mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
                }
            }
            mVolumeController.setLayoutDirection(config.getLayoutDirection());
        } catch (Exception e) {
            Log.e(TAG, "Error handling configuration change: ", e);
        }
    
private booleanhandleDeviceConnection(boolean connected, int device, java.lang.String params)

        synchronized (mConnectedDevices) {
            boolean isConnected = (mConnectedDevices.containsKey(device) &&
                    (params.isEmpty() || mConnectedDevices.get(device).equals(params)));

            if (isConnected && !connected) {
                AudioSystem.setDeviceConnectionState(device,
                                              AudioSystem.DEVICE_STATE_UNAVAILABLE,
                                              mConnectedDevices.get(device));
                 mConnectedDevices.remove(device);
                 return true;
            } else if (!isConnected && connected) {
                 AudioSystem.setDeviceConnectionState(device,
                                                      AudioSystem.DEVICE_STATE_AVAILABLE,
                                                      params);
                 mConnectedDevices.put(new Integer(device), params);
                 return true;
            }
        }
        return false;
    
private booleanhasRmtSbmxFullVolDeathHandlerFor(android.os.IBinder cb)
call synchronized on mRmtSbmxFullVolDeathHandlers

        Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
        while (it.hasNext()) {
            if (it.next().isHandlerFor(cb)) {
                return true;
            }
        }
        return false;
    
private booleanhasScheduledA2dpDockTimeout()

        return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
    
private booleanisAfMusicActiveRecently(int delay_ms)
For code clarity for getActiveStreamType(int)

param
delay_ms max time since last STREAM_MUSIC activity to consider
return
true if STREAM_MUSIC is active in streams handled by AudioFlinger now or in the last "delay_ms" ms.

        return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
                || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
    
public booleanisBluetoothA2dpOn()

see
AudioManager#isBluetoothA2dpOn()

        synchronized (mBluetoothA2dpEnabledLock) {
            return mBluetoothA2dpEnabled;
        }
    
public booleanisBluetoothScoOn()

see
AudioManager#isBluetoothScoOn()

        return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
    
public booleanisCameraSoundForced()

        synchronized (mCameraSoundForced) {
            return mCameraSoundForced;
        }
    
public booleanisHdmiSystemAudioSupported()

        return mHdmiSystemAudioSupported;
    
private booleanisInCommunication()

        boolean IsInCall = false;

        TelecomManager telecomManager =
                (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);

        final long ident = Binder.clearCallingIdentity();
        IsInCall = telecomManager.isInCall();
        Binder.restoreCallingIdentity(ident);

        return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
    
public booleanisMasterMute()
get master mute state.

        return AudioSystem.getMasterMute();
    
private booleanisPlatformTelevision()

        return mPlatformType == PLATFORM_TELEVISION;
    
private booleanisPlatformVoice()


       
        return mPlatformType == PLATFORM_VOICE;
    
public booleanisSpeakerphoneOn()

see
AudioManager#isSpeakerphoneOn()

        return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
    
public booleanisStreamAffectedByMute(int streamType)

        return (mMuteAffectedStreams & (1 << streamType)) != 0;
    
public booleanisStreamAffectedByRingerMode(int streamType)

        return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
    
public booleanisStreamMute(int streamType)
get stream mute state.

        if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
            streamType = getActiveStreamType(streamType);
        }
        synchronized (VolumeStreamState.class) {
            return mStreamStates[streamType].isMuted_syncVSS();
        }
    
private booleanisStreamMutedByRingerMode(int streamType)

        return (mRingerModeMutedStreams & (1 << streamType)) != 0;
    
public booleanisValidRingerMode(int ringerMode)

see
AudioManager#isValidRingerMode(int)

        return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
    
public booleanloadSoundEffects()
Loads samples into the soundpool. This method must be called at first when sound effects are enabled

        int attempts = 3;
        LoadSoundEffectReply reply = new LoadSoundEffectReply();

        synchronized (reply) {
            sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
            while ((reply.mStatus == 1) && (attempts-- > 0)) {
                try {
                    reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
                } catch (InterruptedException e) {
                    Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
                }
            }
        }
        return (reply.mStatus == 0);
    
private voidloadTouchSoundAssetDefaults()

    

       
        SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
        for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
            SOUND_EFFECT_FILES_MAP[i][0] = 0;
            SOUND_EFFECT_FILES_MAP[i][1] = -1;
        }
    
private voidloadTouchSoundAssets()

        XmlResourceParser parser = null;

        // only load assets once.
        if (!SOUND_EFFECT_FILES.isEmpty()) {
            return;
        }

        loadTouchSoundAssetDefaults();

        try {
            parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);

            XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
            String version = parser.getAttributeValue(null, ATTR_VERSION);
            boolean inTouchSoundsGroup = false;

            if (ASSET_FILE_VERSION.equals(version)) {
                while (true) {
                    XmlUtils.nextElement(parser);
                    String element = parser.getName();
                    if (element == null) {
                        break;
                    }
                    if (element.equals(TAG_GROUP)) {
                        String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
                        if (GROUP_TOUCH_SOUNDS.equals(name)) {
                            inTouchSoundsGroup = true;
                            break;
                        }
                    }
                }
                while (inTouchSoundsGroup) {
                    XmlUtils.nextElement(parser);
                    String element = parser.getName();
                    if (element == null) {
                        break;
                    }
                    if (element.equals(TAG_ASSET)) {
                        String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
                        String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
                        int fx;

                        try {
                            Field field = AudioManager.class.getField(id);
                            fx = field.getInt(null);
                        } catch (Exception e) {
                            Log.w(TAG, "Invalid touch sound ID: "+id);
                            continue;
                        }

                        int i = SOUND_EFFECT_FILES.indexOf(file);
                        if (i == -1) {
                            i = SOUND_EFFECT_FILES.size();
                            SOUND_EFFECT_FILES.add(file);
                        }
                        SOUND_EFFECT_FILES_MAP[fx][0] = i;
                    } else {
                        break;
                    }
                }
            }
        } catch (Resources.NotFoundException e) {
            Log.w(TAG, "audio assets file not found", e);
        } catch (XmlPullParserException e) {
            Log.w(TAG, "XML parser exception reading touch sound assets", e);
        } catch (IOException e) {
            Log.w(TAG, "I/O exception reading touch sound assets", e);
        } finally {
            if (parser != null) {
                parser.close();
            }
        }
    
private voidmakeA2dpDeviceAvailable(java.lang.String address)

        // enable A2DP before notifying A2DP connection to avoid unecessary processing in
        // audio policy manager
        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
        sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
        setBluetoothA2dpOnInt(true);
        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
                AudioSystem.DEVICE_STATE_AVAILABLE,
                address);
        // Reset A2DP suspend state each time a new sink is connected
        AudioSystem.setParameters("A2dpSuspended=false");
        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
                address);
    
private voidmakeA2dpDeviceUnavailableLater(java.lang.String address)

        // prevent any activity on the A2DP audio output to avoid unwanted
        // reconnection of the sink.
        AudioSystem.setParameters("A2dpSuspended=true");
        // the device will be made unavailable later, so consider it disconnected right away
        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
        // send the delayed message to make the device unavailable later
        Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
        mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);

    
private voidmakeA2dpDeviceUnavailableNow(java.lang.String address)

        synchronized (mA2dpAvrcpLock) {
            mAvrcpAbsVolSupported = false;
        }
        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
                AudioSystem.DEVICE_STATE_UNAVAILABLE,
                address);
        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
        synchronized (mCurAudioRoutes) {
            // Remove A2DP routes as well
            if (mCurAudioRoutes.mBluetoothName != null) {
                mCurAudioRoutes.mBluetoothName = null;
                sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
                        SENDMSG_NOOP, 0, 0, null, 0);
            }
        }
    
private voidmakeA2dpSrcAvailable(java.lang.String address)

        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
                AudioSystem.DEVICE_STATE_AVAILABLE,
                address);
        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP),
                address);
    
private voidmakeA2dpSrcUnavailable(java.lang.String address)

        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
                AudioSystem.DEVICE_STATE_UNAVAILABLE,
                address);
        mConnectedDevices.remove(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
    
public voidnotifyVolumeControllerVisible(IVolumeController controller, boolean visible)

        enforceSelfOrSystemUI("notify about volume controller visibility");

        // return early if the controller is not current
        if (!mVolumeController.isSameBinder(controller)) {
            return;
        }

        mVolumeController.setVisible(visible);
        if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
    
private voidonBroadcastScoConnectionState(int state)

        if (state != mScoConnectionState) {
            Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
                    mScoConnectionState);
            sendStickyBroadcastToAll(newIntent);
            mScoConnectionState = state;
        }
    
private voidonCheckMusicActive()


       
        synchronized (mSafeMediaVolumeState) {
            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
                int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);

                if ((device & mSafeMediaVolumeDevices) != 0) {
                    sendMsg(mAudioHandler,
                            MSG_CHECK_MUSIC_ACTIVE,
                            SENDMSG_REPLACE,
                            0,
                            0,
                            null,
                            MUSIC_ACTIVE_POLL_PERIOD_MS);
                    int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
                    if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
                            (index > mSafeMediaVolumeIndex)) {
                        // Approximate cumulative active music time
                        mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
                        if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
                            setSafeMediaVolumeEnabled(true);
                            mMusicActiveMs = 0;
                        }
                        saveMusicActiveMs();
                    }
                }
            }
        }
    
private voidonConfigureSafeVolume(boolean force)

        synchronized (mSafeMediaVolumeState) {
            int mcc = mContext.getResources().getConfiguration().mcc;
            if ((mMcc != mcc) || ((mMcc == 0) && force)) {
                mSafeMediaVolumeIndex = mContext.getResources().getInteger(
                        com.android.internal.R.integer.config_safe_media_volume_index) * 10;
                boolean safeMediaVolumeEnabled =
                        SystemProperties.getBoolean("audio.safemedia.force", false)
                        || mContext.getResources().getBoolean(
                                com.android.internal.R.bool.config_safe_media_volume_enabled);

                // The persisted state is either "disabled" or "active": this is the state applied
                // next time we boot and cannot be "inactive"
                int persistedState;
                if (safeMediaVolumeEnabled) {
                    persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
                    // The state can already be "inactive" here if the user has forced it before
                    // the 30 seconds timeout for forced configuration. In this case we don't reset
                    // it to "active".
                    if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
                        if (mMusicActiveMs == 0) {
                            mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
                            enforceSafeMediaVolume();
                        } else {
                            // We have existing playback time recorded, already confirmed.
                            mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
                        }
                    }
                } else {
                    persistedState = SAFE_MEDIA_VOLUME_DISABLED;
                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
                }
                mMcc = mcc;
                sendMsg(mAudioHandler,
                        MSG_PERSIST_SAFE_VOLUME_STATE,
                        SENDMSG_QUEUE,
                        persistedState,
                        0,
                        null,
                        0);
            }
        }
    
private voidonSendBecomingNoisyIntent()

        sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
    
private voidonSetA2dpSinkConnectionState(android.bluetooth.BluetoothDevice btDevice, int state)

        if (DEBUG_VOL) {
            Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
        }
        if (btDevice == null) {
            return;
        }
        String address = btDevice.getAddress();
        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
            address = "";
        }

        synchronized (mConnectedDevices) {
            boolean isConnected =
                (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
                 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));

            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
                if (btDevice.isBluetoothDock()) {
                    if (state == BluetoothProfile.STATE_DISCONNECTED) {
                        // introduction of a delay for transient disconnections of docks when
                        // power is rapidly turned off/on, this message will be canceled if
                        // we reconnect the dock under a preset delay
                        makeA2dpDeviceUnavailableLater(address);
                        // the next time isConnected is evaluated, it will be false for the dock
                    }
                } else {
                    makeA2dpDeviceUnavailableNow(address);
                }
                synchronized (mCurAudioRoutes) {
                    if (mCurAudioRoutes.mBluetoothName != null) {
                        mCurAudioRoutes.mBluetoothName = null;
                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
                                SENDMSG_NOOP, 0, 0, null, 0);
                    }
                }
            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
                if (btDevice.isBluetoothDock()) {
                    // this could be a reconnection after a transient disconnection
                    cancelA2dpDeviceTimeout();
                    mDockAddress = address;
                } else {
                    // this could be a connection of another A2DP device before the timeout of
                    // a dock: cancel the dock timeout, and make the dock unavailable now
                    if(hasScheduledA2dpDockTimeout()) {
                        cancelA2dpDeviceTimeout();
                        makeA2dpDeviceUnavailableNow(mDockAddress);
                    }
                }
                makeA2dpDeviceAvailable(address);
                synchronized (mCurAudioRoutes) {
                    String name = btDevice.getAliasName();
                    if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) {
                        mCurAudioRoutes.mBluetoothName = name;
                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
                                SENDMSG_NOOP, 0, 0, null, 0);
                    }
                }
            }
        }
    
private voidonSetA2dpSourceConnectionState(android.bluetooth.BluetoothDevice btDevice, int state)

        if (DEBUG_VOL) {
            Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
        }
        if (btDevice == null) {
            return;
        }
        String address = btDevice.getAddress();
        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
            address = "";
        }

        synchronized (mConnectedDevices) {
                boolean isConnected =
                (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) &&
                 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP).equals(address));

            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
                makeA2dpSrcUnavailable(address);
            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
                makeA2dpSrcAvailable(address);
            }
        }
    
private voidonSetStreamVolume(int streamType, int index, int flags, int device)

        setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
        // setting volume on master stream type also controls silent mode
        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
                (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
            int newRingerMode;
            if (index == 0) {
                newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
                        : VOLUME_SETS_RINGER_MODE_SILENT ? AudioManager.RINGER_MODE_SILENT
                        : AudioManager.RINGER_MODE_NORMAL;
            } else {
                newRingerMode = AudioManager.RINGER_MODE_NORMAL;
            }
            setRingerMode(newRingerMode, TAG + ".onSetStreamVolume", false /*external*/);
        }
    
private voidonSetWiredDeviceConnectionState(int device, int state, java.lang.String name)

        synchronized (mConnectedDevices) {
            if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
                    (device == AudioSystem.DEVICE_OUT_LINE))) {
                setBluetoothA2dpOnInt(true);
            }
            boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
                            (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
                             ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
            handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
            if (state != 0) {
                if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
                    (device == AudioSystem.DEVICE_OUT_LINE)) {
                    setBluetoothA2dpOnInt(false);
                }
                if ((device & mSafeMediaVolumeDevices) != 0) {
                    sendMsg(mAudioHandler,
                            MSG_CHECK_MUSIC_ACTIVE,
                            SENDMSG_REPLACE,
                            0,
                            0,
                            null,
                            MUSIC_ACTIVE_POLL_PERIOD_MS);
                }
                // Television devices without CEC service apply software volume on HDMI output
                if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
                    mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
                    checkAllFixedVolumeDevices();
                    if (mHdmiManager != null) {
                        synchronized (mHdmiManager) {
                            if (mHdmiPlaybackClient != null) {
                                mHdmiCecSink = false;
                                mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
                            }
                        }
                    }
                }
            } else {
                if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
                    if (mHdmiManager != null) {
                        synchronized (mHdmiManager) {
                            mHdmiCecSink = false;
                        }
                    }
                }
            }
            if (!isUsb && (device != AudioSystem.DEVICE_IN_WIRED_HEADSET)) {
                sendDeviceConnectionIntent(device, state, name);
            }
        }
    
public voidonSystemReady()

        mSystemReady = true;
        sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
                0, 0, null, 0);

        mKeyguardManager =
                (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
        mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
        resetBluetoothSco();
        getBluetoothHeadset();
        //FIXME: this is to maintain compatibility with deprecated intent
        // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
        Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
        newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
        sendStickyBroadcastToAll(newIntent);

        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        if (adapter != null) {
            adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
                                    BluetoothProfile.A2DP);
        }

        mHdmiManager =
                (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
        if (mHdmiManager != null) {
            synchronized (mHdmiManager) {
                mHdmiTvClient = mHdmiManager.getTvClient();
                if (mHdmiTvClient != null) {
                    mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
                }
                mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
                mHdmiCecSink = false;
            }
        }

        sendMsg(mAudioHandler,
                MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
                SENDMSG_REPLACE,
                0,
                0,
                null,
                SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);

        StreamOverride.init(mContext);
    
public voidplaySoundEffect(int effectType)

see
AudioManager#playSoundEffect(int)

        playSoundEffectVolume(effectType, -1.0f);
    
public voidplaySoundEffectVolume(int effectType, float volume)

see
AudioManager#playSoundEffect(int, float)

        if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
            Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
            return;
        }

        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
                effectType, (int) (volume * 1000), null, 0);
    
private voidqueueMsgUnderWakeLock(android.os.Handler handler, int msg, int arg1, int arg2, java.lang.Object obj, int delay)
Queue a message on the given handler's message queue, after acquiring the service wake lock. Note that the wake lock needs to be released after the message has been handled.

        final long ident = Binder.clearCallingIdentity();
        // Always acquire the wake lock as AudioService because it is released by the
        // message handler.
        mAudioEventWakeLock.acquire();
        Binder.restoreCallingIdentity(ident);
        sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
    
private static voidreadAndSetLowRamDevice()

        int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
        if (status != 0) {
            Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
        }
    
private voidreadAudioSettings(boolean userSwitch)

        // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
        readPersistedSettings();

        // restore volume settings
        int numStreamTypes = AudioSystem.getNumStreamTypes();
        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
            VolumeStreamState streamState = mStreamStates[streamType];

            if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
                continue;
            }

            streamState.readSettings();
            synchronized (VolumeStreamState.class) {
                // unmute stream that was muted but is not affect by mute anymore
                if (streamState.isMuted_syncVSS() && ((!isStreamAffectedByMute(streamType) &&
                        !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
                    int size = streamState.mDeathHandlers.size();
                    for (int i = 0; i < size; i++) {
                        streamState.mDeathHandlers.get(i).mMuteCount = 1;
                        streamState.mDeathHandlers.get(i).mute_syncVSS(false);
                    }
                }
            }
        }

        // apply new ringer mode before checking volume for alias streams so that streams
        // muted by ringer mode have the correct volume
        setRingerModeInt(getRingerModeInternal(), false);

        checkAllFixedVolumeDevices();
        checkAllAliasStreamVolumes();

        synchronized (mSafeMediaVolumeState) {
            mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
                    Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
                    0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
                enforceSafeMediaVolume();
            }
        }
    
private voidreadDockAudioSettings(android.content.ContentResolver cr)

        mDockAudioMediaEnabled = Settings.Global.getInt(
                                        cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;

        if (mDockAudioMediaEnabled) {
            mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
        } else {
            mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
        }

        sendMsg(mAudioHandler,
                MSG_SET_FORCE_USE,
                SENDMSG_QUEUE,
                AudioSystem.FOR_DOCK,
                mDockAudioMediaEnabled ?
                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
                null,
                0);
    
private voidreadPersistedSettings()

        final ContentResolver cr = mContentResolver;

        int ringerModeFromSettings =
                Settings.Global.getInt(
                        cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
        int ringerMode = ringerModeFromSettings;
        // sanity check in case the settings are restored from a device with incompatible
        // ringer modes
        if (!isValidRingerMode(ringerMode)) {
            ringerMode = AudioManager.RINGER_MODE_NORMAL;
        }
        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
            ringerMode = AudioManager.RINGER_MODE_SILENT;
        }
        if (ringerMode != ringerModeFromSettings) {
            Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
        }
        if (mUseFixedVolume || isPlatformTelevision()) {
            ringerMode = AudioManager.RINGER_MODE_NORMAL;
        }
        synchronized(mSettingsLock) {
            mRingerMode = ringerMode;
            if (mRingerModeExternal == -1) {
                mRingerModeExternal = mRingerMode;
            }

            // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
            // are still needed while setVibrateSetting() and getVibrateSetting() are being
            // deprecated.
            mVibrateSetting = getValueForVibrateSetting(0,
                                            AudioManager.VIBRATE_TYPE_NOTIFICATION,
                                            mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
                                                            : AudioManager.VIBRATE_SETTING_OFF);
            mVibrateSetting = getValueForVibrateSetting(mVibrateSetting,
                                            AudioManager.VIBRATE_TYPE_RINGER,
                                            mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
                                                            : AudioManager.VIBRATE_SETTING_OFF);

            updateRingerModeAffectedStreams();
            readDockAudioSettings(cr);
        }

        mMuteAffectedStreams = System.getIntForUser(cr,
                System.MUTE_STREAMS_AFFECTED,
                ((1 << AudioSystem.STREAM_MUSIC)|
                 (1 << AudioSystem.STREAM_RING)|
                 (1 << AudioSystem.STREAM_SYSTEM)),
                 UserHandle.USER_CURRENT);

        boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
                                                  0, UserHandle.USER_CURRENT) == 1;
        if (mUseFixedVolume) {
            masterMute = false;
            AudioSystem.setMasterVolume(1.0f);
        }
        AudioSystem.setMasterMute(masterMute);
        broadcastMasterMuteStatus(masterMute);

        boolean microphoneMute =
                System.getIntForUser(cr, System.MICROPHONE_MUTE, 0, UserHandle.USER_CURRENT) == 1;
        AudioSystem.muteMicrophone(microphoneMute);

        // Each stream will read its own persisted settings

        // Broadcast the sticky intents
        broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
        broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);

        // Broadcast vibrate settings
        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);

        // Load settings for the volume controller
        mVolumeController.loadSettings(cr);
    
public java.lang.StringregisterAudioPolicy(android.media.audiopolicy.AudioPolicyConfig policyConfig, android.media.audiopolicy.IAudioPolicyCallback pcb, boolean hasFocusListener)

        if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
                + " with config:" + policyConfig);
        String regId = null;
        // error handling
        boolean hasPermissionForPolicy =
                (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
                        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 null;
        }

        synchronized (mAudioPolicies) {
            try {
                if (mAudioPolicies.containsKey(pcb.asBinder())) {
                    Slog.e(TAG, "Cannot re-register policy");
                    return null;
                }
                AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener);
                pcb.asBinder().linkToDeath(app, 0/*flags*/);
                regId = app.getRegistrationId();
                mAudioPolicies.put(pcb.asBinder(), app);
            } catch (RemoteException e) {
                // audio policy owner has already died!
                Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
                        " binder death", e);
                return null;
            }
        }
        return regId;
    
public booleanregisterRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h)

        return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
    
public booleanregisterRemoteController(IRemoteControlDisplay rcd, int w, int h, android.content.ComponentName listenerComp)

        return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
    
public voidreloadAudioSettings()

see
AudioManager#reloadAudioSettings()

        readAudioSettings(false /*userSwitch*/);
    
public voidremoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h)

        mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
    
public voidremoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd, boolean wantsSync)

        mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
    
public intrequestAudioFocus(AudioAttributes aa, int durationHint, android.os.IBinder cb, IAudioFocusDispatcher fd, java.lang.String clientId, java.lang.String callingPackageName, int flags, android.media.audiopolicy.IAudioPolicyCallback pcb)

        // permission checks
        if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
            if (mMediaFocusControl.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
                if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
                            android.Manifest.permission.MODIFY_PHONE_STATE)) {
                    Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
                    return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
                }
            } else {
                // only a registered audio policy can be used to lock focus
                synchronized (mAudioPolicies) {
                    if (!mAudioPolicies.containsKey(pcb.asBinder())) {
                        Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
                        return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
                    }
                }
            }
        }

        return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
                clientId, callingPackageName, flags);
    
private intrescaleIndex(int index, int srcStream, int dstStream)

        return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
    
private voidresetBluetoothSco()

        synchronized(mScoClients) {
            clearAllScoClients(0, false);
            mScoAudioState = SCO_STATE_INACTIVE;
            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
        }
    
private voidrestoreMasterVolume()

        if (mUseFixedVolume) {
            AudioSystem.setMasterVolume(1.0f);
            return;
        }
        if (mUseMasterVolume) {
            float volume = Settings.System.getFloatForUser(mContentResolver,
                    Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT);
            if (volume >= 0.0f) {
                AudioSystem.setMasterVolume(volume);
            }
        }
    
private static java.lang.StringsafeMediaVolumeStateToString(java.lang.Integer state)

        switch(state) {
            case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
            case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
            case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
            case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
        }
        return null;
    
private voidsaveMusicActiveMs()

        mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
    
private voidsendBroadcastToAll(android.content.Intent intent)

        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
        final long ident = Binder.clearCallingIdentity();
        try {
            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    
private voidsendDeviceConnectionIntent(int device, int state, java.lang.String name)

        Intent intent = new Intent();

        intent.putExtra("state", state);
        intent.putExtra("name", name);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);

        int connType = 0;

        if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
            connType = AudioRoutesInfo.MAIN_HEADSET;
            intent.setAction(Intent.ACTION_HEADSET_PLUG);
            intent.putExtra("microphone", 1);
        } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
                   device == AudioSystem.DEVICE_OUT_LINE) {
            /*do apps care about line-out vs headphones?*/
            connType = AudioRoutesInfo.MAIN_HEADPHONES;
            intent.setAction(Intent.ACTION_HEADSET_PLUG);
            intent.putExtra("microphone", 0);
        } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) {
            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
            intent.setAction(AudioManager.ACTION_ANALOG_AUDIO_DOCK_PLUG);
        } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {
            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
            intent.setAction(AudioManager.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
        } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
                device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
            connType = AudioRoutesInfo.MAIN_HDMI;
            configureHdmiPlugIntent(intent, state);
        }

        synchronized (mCurAudioRoutes) {
            if (connType != 0) {
                int newConn = mCurAudioRoutes.mMainType;
                if (state != 0) {
                    newConn |= connType;
                } else {
                    newConn &= ~connType;
                }
                if (newConn != mCurAudioRoutes.mMainType) {
                    mCurAudioRoutes.mMainType = newConn;
                    sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
                            SENDMSG_NOOP, 0, 0, null, 0);
                }
            }
        }

        final long ident = Binder.clearCallingIdentity();
        try {
            ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    
private voidsendMasterMuteUpdate(boolean muted, int flags)

        mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
        broadcastMasterMuteStatus(muted);
    
private voidsendMasterVolumeUpdate(int flags, int oldVolume, int newVolume)

        mVolumeController.postMasterVolumeChanged(updateFlagsForSystemAudio(flags));

        Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
        intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
        sendBroadcastToAll(intent);
    
private static voidsendMsg(android.os.Handler handler, int msg, int existingMsgPolicy, int arg1, int arg2, java.lang.Object obj, int delay)


        if (existingMsgPolicy == SENDMSG_REPLACE) {
            handler.removeMessages(msg);
        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
            return;
        }
        synchronized (mLastDeviceConnectMsgTime) {
            long time = SystemClock.uptimeMillis() + delay;
            handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
            if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
                    msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
                    msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
                mLastDeviceConnectMsgTime = time;
            }
        }
    
private voidsendStickyBroadcastToAll(android.content.Intent intent)

        final long ident = Binder.clearCallingIdentity();
        try {
            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    
private voidsendVolumeUpdate(int streamType, int oldIndex, int index, int flags)

        if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) {
            streamType = AudioSystem.STREAM_NOTIFICATION;
        }

        if (streamType == AudioSystem.STREAM_MUSIC) {
            flags = updateFlagsForSystemAudio(flags);
        }
        mVolumeController.postVolumeChanged(streamType, flags);

        if ((flags & AudioManager.FLAG_FIXED_VOLUME) == 0) {
            oldIndex = (oldIndex + 5) / 10;
            index = (index + 5) / 10;
            Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
            intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
            sendBroadcastToAll(intent);
        }
    
public intsetBluetoothA2dpDeviceConnectionState(android.bluetooth.BluetoothDevice device, int state, int profile)

        int delay;
        if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
            throw new IllegalArgumentException("invalid profile " + profile);
        }
        synchronized (mConnectedDevices) {
            if (profile == BluetoothProfile.A2DP) {
                delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
                                                (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
            } else {
                delay = 0;
            }
            queueMsgUnderWakeLock(mAudioHandler,
                    (profile == BluetoothProfile.A2DP ?
                        MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
                    state,
                    0,
                    device,
                    delay);
        }
        return delay;
    
public voidsetBluetoothA2dpOn(boolean on)

see
AudioManager#setBluetoothA2dpOn(boolean)

        synchronized (mBluetoothA2dpEnabledLock) {
            mBluetoothA2dpEnabled = on;
            sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
                    AudioSystem.FOR_MEDIA,
                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
                    null, 0);
        }
    
public voidsetBluetoothA2dpOnInt(boolean on)

        synchronized (mBluetoothA2dpEnabledLock) {
            mBluetoothA2dpEnabled = on;
            mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
            AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
        }
    
public voidsetBluetoothScoOn(boolean on)

see
AudioManager#setBluetoothScoOn(boolean)

        if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
            return;
        }

        if (on) {
            mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
        } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
            mForcedUseForComm = AudioSystem.FORCE_NONE;
        }

        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
                AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
    
public intsetFocusPropertiesForPolicy(int duckingBehavior, android.media.audiopolicy.IAudioPolicyCallback pcb)

        if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
                + " policy " +  pcb.asBinder());
        // error handling
        boolean hasPermissionForPolicy =
                (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
                        android.Manifest.permission.MODIFY_AUDIO_ROUTING));
        if (!hasPermissionForPolicy) {
            Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
                    + Binder.getCallingPid() + " / uid "
                    + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
            return AudioManager.ERROR;
        }

        synchronized (mAudioPolicies) {
            if (!mAudioPolicies.containsKey(pcb.asBinder())) {
                Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
                return AudioManager.ERROR;
            }
            final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
            if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
                // is there already one policy managing ducking?
                for(AudioPolicyProxy policy : mAudioPolicies.values()) {
                    if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
                        Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
                        return AudioManager.ERROR;
                    }
                }
            }
            app.mFocusDuckBehavior = duckingBehavior;
            mMediaFocusControl.setDuckingInExtPolicyAvailable(
                    duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
        }
        return AudioManager.SUCCESS;
    
public intsetHdmiSystemAudioSupported(boolean on)


    
        
        int device = AudioSystem.DEVICE_NONE;
        if (mHdmiManager != null) {
            synchronized (mHdmiManager) {
                if (mHdmiTvClient == null) {
                    Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
                    return device;
                }

                synchronized (mHdmiTvClient) {
                    if (mHdmiSystemAudioSupported != on) {
                        mHdmiSystemAudioSupported = on;
                        AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
                                on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
                                     AudioSystem.FORCE_NONE);
                    }
                    device = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
                }
            }
        }
        return device;
    
public voidsetMasterMute(boolean state, int flags, java.lang.String callingPackage, android.os.IBinder cb)

see
AudioManager#setMasterMute(boolean, int)

        setMasterMuteInternal(state, flags, callingPackage, cb, Binder.getCallingUid());
    
private voidsetMasterMuteInternal(boolean state, int flags, java.lang.String callingPackage, android.os.IBinder cb, int uid)

        if (mUseFixedVolume) {
            return;
        }
        if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
                != AppOpsManager.MODE_ALLOWED) {
            return;
        }
        if (state != AudioSystem.getMasterMute()) {
            setSystemAudioMute(state);
            AudioSystem.setMasterMute(state);
            // Post a persist master volume msg
            sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
                    : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
            sendMasterMuteUpdate(state, flags);

            Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
            intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, state);
            sendBroadcastToAll(intent);
        }
    
public voidsetMasterVolume(int volume, int flags, java.lang.String callingPackage)

        setMasterVolume(volume, flags, callingPackage, Binder.getCallingUid());
    
public voidsetMasterVolume(int volume, int flags, java.lang.String callingPackage, int uid)

        if (mUseFixedVolume) {
            return;
        }

        if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
                != AppOpsManager.MODE_ALLOWED) {
            return;
        }

        if (volume < 0) {
            volume = 0;
        } else if (volume > MAX_MASTER_VOLUME) {
            volume = MAX_MASTER_VOLUME;
        }
        doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
    
public voidsetMicrophoneMute(boolean on, java.lang.String callingPackage)

see
AudioManager#setMicrophoneMute(boolean)

        if (mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, Binder.getCallingUid(),
                callingPackage) != AppOpsManager.MODE_ALLOWED) {
            return;
        }
        if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
            return;
        }

        AudioSystem.muteMicrophone(on);
        // Post a persist microphone msg.
        sendMsg(mAudioHandler, MSG_PERSIST_MICROPHONE_MUTE, SENDMSG_REPLACE, on ? 1
                : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
    
public voidsetMode(int mode, android.os.IBinder cb)

see
AudioManager#setMode(int)

        if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ")"); }
        if (!checkAudioSettingsPermission("setMode()")) {
            return;
        }

        if ( (mode == AudioSystem.MODE_IN_CALL) &&
                (mContext.checkCallingOrSelfPermission(
                        android.Manifest.permission.MODIFY_PHONE_STATE)
                            != PackageManager.PERMISSION_GRANTED)) {
            Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
            return;
        }

        if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
            return;
        }

        int newModeOwnerPid = 0;
        synchronized(mSetModeDeathHandlers) {
            if (mode == AudioSystem.MODE_CURRENT) {
                mode = mMode;
            }
            newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
        }
        // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
        // SCO connections not started by the application changing the mode
        if (newModeOwnerPid != 0) {
             disconnectBluetoothSco(newModeOwnerPid);
        }
    
private intsetModeInt(int mode, android.os.IBinder cb, int pid)

        if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ")"); }
        int newModeOwnerPid = 0;
        if (cb == null) {
            Log.e(TAG, "setModeInt() called with null binder");
            return newModeOwnerPid;
        }

        SetModeDeathHandler hdlr = null;
        Iterator iter = mSetModeDeathHandlers.iterator();
        while (iter.hasNext()) {
            SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
            if (h.getPid() == pid) {
                hdlr = h;
                // Remove from client list so that it is re-inserted at top of list
                iter.remove();
                hdlr.getBinder().unlinkToDeath(hdlr, 0);
                break;
            }
        }
        int status = AudioSystem.AUDIO_STATUS_OK;
        do {
            if (mode == AudioSystem.MODE_NORMAL) {
                // get new mode from client at top the list if any
                if (!mSetModeDeathHandlers.isEmpty()) {
                    hdlr = mSetModeDeathHandlers.get(0);
                    cb = hdlr.getBinder();
                    mode = hdlr.getMode();
                    if (DEBUG_MODE) {
                        Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
                                + hdlr.mPid);
                    }
                }
            } else {
                if (hdlr == null) {
                    hdlr = new SetModeDeathHandler(cb, pid);
                }
                // Register for client death notification
                try {
                    cb.linkToDeath(hdlr, 0);
                } catch (RemoteException e) {
                    // Client has died!
                    Log.w(TAG, "setMode() could not link to "+cb+" binder death");
                }

                // Last client to call setMode() is always at top of client list
                // as required by SetModeDeathHandler.binderDied()
                mSetModeDeathHandlers.add(0, hdlr);
                hdlr.setMode(mode);
            }

            if (mode != mMode) {
                status = AudioSystem.setPhoneState(mode);
                if (status == AudioSystem.AUDIO_STATUS_OK) {
                    if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
                    mMode = mode;
                } else {
                    if (hdlr != null) {
                        mSetModeDeathHandlers.remove(hdlr);
                        cb.unlinkToDeath(hdlr, 0);
                    }
                    // force reading new top of mSetModeDeathHandlers stack
                    if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
                    mode = AudioSystem.MODE_NORMAL;
                }
            } else {
                status = AudioSystem.AUDIO_STATUS_OK;
            }
        } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());

        if (status == AudioSystem.AUDIO_STATUS_OK) {
            if (mode != AudioSystem.MODE_NORMAL) {
                if (mSetModeDeathHandlers.isEmpty()) {
                    Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
                } else {
                    newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
                }
            }
            int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
            int device = getDeviceForStream(streamType);
            int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
            setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true);

            updateStreamVolumeAlias(true /*updateVolumes*/);
        }
        return newModeOwnerPid;
    
private voidsetOrientationForAudioSystem()

        switch (mDeviceOrientation) {
            case Configuration.ORIENTATION_LANDSCAPE:
                //Log.i(TAG, "orientation is landscape");
                AudioSystem.setParameters("orientation=landscape");
                break;
            case Configuration.ORIENTATION_PORTRAIT:
                //Log.i(TAG, "orientation is portrait");
                AudioSystem.setParameters("orientation=portrait");
                break;
            case Configuration.ORIENTATION_SQUARE:
                //Log.i(TAG, "orientation is square");
                AudioSystem.setParameters("orientation=square");
                break;
            case Configuration.ORIENTATION_UNDEFINED:
                //Log.i(TAG, "orientation is undefined");
                AudioSystem.setParameters("orientation=undefined");
                break;
            default:
                Log.e(TAG, "Unknown orientation");
        }
    
public voidsetRemoteStreamVolume(int index)

        enforceSelfOrSystemUI("set the remote stream volume");
        mMediaFocusControl.setRemoteStreamVolume(index);
    
private voidsetRingerMode(int ringerMode, java.lang.String caller, boolean external)

        if (mUseFixedVolume || isPlatformTelevision()) {
            return;
        }
        if (caller == null || caller.length() == 0) {
            throw new IllegalArgumentException("Bad caller: " + caller);
        }
        ensureValidRingerMode(ringerMode);
        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
            ringerMode = AudioManager.RINGER_MODE_SILENT;
        }
        final long identity = Binder.clearCallingIdentity();
        try {
            synchronized (mSettingsLock) {
                final int ringerModeInternal = getRingerModeInternal();
                final int ringerModeExternal = getRingerModeExternal();
                if (external) {
                    setRingerModeExt(ringerMode);
                    if (mRingerModeDelegate != null) {
                        ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
                                ringerMode, caller, ringerModeInternal);
                    }
                    if (ringerMode != ringerModeInternal) {
                        setRingerModeInt(ringerMode, true /*persist*/);
                    }
                } else /*internal*/ {
                    if (ringerMode != ringerModeInternal) {
                        setRingerModeInt(ringerMode, true /*persist*/);
                    }
                    if (mRingerModeDelegate != null) {
                        ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
                                ringerMode, caller, ringerModeExternal);
                    }
                    setRingerModeExt(ringerMode);
                }
            }
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    
private voidsetRingerModeExt(int ringerMode)

        synchronized(mSettingsLock) {
            if (ringerMode == mRingerModeExternal) return;
            mRingerModeExternal = ringerMode;
        }
        // Send sticky broadcast
        broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
    
public voidsetRingerModeExternal(int ringerMode, java.lang.String caller)

        setRingerMode(ringerMode, caller, true /*external*/);
    
private voidsetRingerModeInt(int ringerMode, boolean persist)

        final boolean change;
        synchronized(mSettingsLock) {
            change = mRingerMode != ringerMode;
            mRingerMode = ringerMode;
        }

        // Mute stream if not previously muted by ringer mode and ringer mode
        // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
        // Unmute stream if previously muted by ringer mode and ringer mode
        // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
        int numStreamTypes = AudioSystem.getNumStreamTypes();
        final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE
                || ringerMode == AudioManager.RINGER_MODE_SILENT;
        for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
            final boolean isMuted = isStreamMutedByRingerMode(streamType);
            final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
            if (isMuted == shouldMute) continue;
            if (!shouldMute) {
                // unmute
                // ring and notifications volume should never be 0 when not silenced
                // on voice capable devices or devices that support vibration
                if ((isPlatformVoice() || mHasVibrator) &&
                        mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
                    synchronized (VolumeStreamState.class) {
                        Set set = mStreamStates[streamType].mIndex.entrySet();
                        Iterator i = set.iterator();
                        while (i.hasNext()) {
                            Map.Entry entry = (Map.Entry)i.next();
                            if ((Integer)entry.getValue() == 0) {
                                entry.setValue(10);
                            }
                        }
                    }
                }
                mStreamStates[streamType].mute(null, false);
                mRingerModeMutedStreams &= ~(1 << streamType);
            } else {
                // mute
                mStreamStates[streamType].mute(null, true);
                mRingerModeMutedStreams |= (1 << streamType);
            }
        }

        // Post a persist ringer mode msg
        if (persist) {
            sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
                    SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
        }
        if (change) {
            // Send sticky broadcast
            broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, ringerMode);
        }
    
public voidsetRingerModeInternal(int ringerMode, java.lang.String caller)

        enforceSelfOrSystemUI("setRingerModeInternal");
        setRingerMode(ringerMode, caller, false /*external*/);
    
public voidsetRingtonePlayer(IRingtonePlayer player)

        mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
        mRingtonePlayer = player;
    
private voidsetRotationForAudioSystem()

        switch (mDeviceRotation) {
            case Surface.ROTATION_0:
                AudioSystem.setParameters("rotation=0");
                break;
            case Surface.ROTATION_90:
                AudioSystem.setParameters("rotation=90");
                break;
            case Surface.ROTATION_180:
                AudioSystem.setParameters("rotation=180");
                break;
            case Surface.ROTATION_270:
                AudioSystem.setParameters("rotation=270");
                break;
            default:
                Log.e(TAG, "Unknown device rotation");
        }
    
private voidsetSafeMediaVolumeEnabled(boolean on)

  // 30s after boot completed

        
        synchronized (mSafeMediaVolumeState) {
            if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
                    (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
                if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
                    enforceSafeMediaVolume();
                } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
                    mMusicActiveMs = 1;  // nonzero = confirmed
                    saveMusicActiveMs();
                    sendMsg(mAudioHandler,
                            MSG_CHECK_MUSIC_ACTIVE,
                            SENDMSG_REPLACE,
                            0,
                            0,
                            null,
                            MUSIC_ACTIVE_POLL_PERIOD_MS);
                }
            }
        }
    
public voidsetSpeakerphoneOn(boolean on)

see
AudioManager#setSpeakerphoneOn(boolean)

        if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
            return;
        }

        if (on) {
            if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
                    sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
                            AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
            }
            mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
        } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
            mForcedUseForComm = AudioSystem.FORCE_NONE;
        }

        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
    
public voidsetStreamMute(int streamType, boolean state, android.os.IBinder cb)

see
AudioManager#setStreamMute(int, boolean)

        if (mUseFixedVolume) {
            return;
        }
        if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
            streamType = getActiveStreamType(streamType);
        }
        int streamAlias = mStreamVolumeAlias[streamType];
        if (isStreamAffectedByMute(streamAlias)) {
            if (streamAlias == AudioSystem.STREAM_MUSIC) {
                setSystemAudioMute(state);
            }
            for (int stream = 0; stream < mStreamStates.length; stream++) {
                if (streamAlias == mStreamVolumeAlias[stream]) {
                    mStreamStates[stream].mute(cb, state);

                    Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
                    intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, stream);
                    intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
                    sendBroadcastToAll(intent);
                }
            }
        }
    
public voidsetStreamSolo(int streamType, boolean state, android.os.IBinder cb)

see
AudioManager#setStreamSolo(int, boolean)

        if (mUseFixedVolume) {
            return;
        }
        int streamAlias = mStreamVolumeAlias[streamType];
        for (int stream = 0; stream < mStreamStates.length; stream++) {
            if (!isStreamAffectedByMute(streamAlias) || streamAlias == mStreamVolumeAlias[stream]) {
                continue;
            }
            mStreamStates[stream].mute(cb, state);
         }
    
public voidsetStreamVolume(int streamType, int index, int flags, java.lang.String callingPackage)

see
AudioManager#setStreamVolume(int, int, int)

        setStreamVolume(streamType, index, flags, callingPackage, Binder.getCallingUid());
    
private voidsetStreamVolume(int streamType, int index, int flags, java.lang.String callingPackage, int uid)

        if (mUseFixedVolume) {
            return;
        }

        ensureValidStreamType(streamType);
        int streamTypeAlias = mStreamVolumeAlias[streamType];
        VolumeStreamState streamState = mStreamStates[streamTypeAlias];

        final int device = getDeviceForStream(streamType);
        int oldIndex;

        // skip a2dp absolute volume control request when the device
        // is not an a2dp device
        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
            return;
        }

        if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
                != AppOpsManager.MODE_ALLOWED) {
            return;
        }

        synchronized (mSafeMediaVolumeState) {
            // reset any pending volume command
            mPendingVolumeCommand = null;

            oldIndex = streamState.getIndex(device);

            index = rescaleIndex(index * 10, streamType, streamTypeAlias);

            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
                synchronized (mA2dpAvrcpLock) {
                    if (mA2dp != null && mAvrcpAbsVolSupported) {
                        mA2dp.setAvrcpAbsoluteVolume(index / 10);
                    }
                }
            }

            if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
                setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
            }

            flags &= ~AudioManager.FLAG_FIXED_VOLUME;
            if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
                    ((device & mFixedVolumeDevices) != 0)) {
                flags |= AudioManager.FLAG_FIXED_VOLUME;

                // volume is either 0 or max allowed for fixed volume devices
                if (index != 0) {
                    if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
                            (device & mSafeMediaVolumeDevices) != 0) {
                        index = mSafeMediaVolumeIndex;
                    } else {
                        index = streamState.getMaxIndex();
                    }
                }
            }

            if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
                mVolumeController.postDisplaySafeVolumeWarning(flags);
                mPendingVolumeCommand = new StreamVolumeCommand(
                                                    streamType, index, flags, device);
            } else {
                onSetStreamVolume(streamType, index, flags, device);
                index = mStreamStates[streamType].getIndex(device);
            }
        }
        sendVolumeUpdate(streamType, oldIndex, index, flags);
    
private voidsetStreamVolumeInt(int streamType, int index, int device, boolean force)
Sets the stream state's index, and posts a message to set system volume. This will not call out to the UI. Assumes a valid stream type.

param
streamType Type of the stream
param
index Desired volume index of the stream
param
device the device whose volume must be changed
param
force If true, set the volume even if the desired volume is same as the current volume.

        VolumeStreamState streamState = mStreamStates[streamType];

        if (streamState.setIndex(index, device) || force) {
            // Post message to set system volume (it in turn will post a message
            // to persist).
            sendMsg(mAudioHandler,
                    MSG_SET_DEVICE_VOLUME,
                    SENDMSG_QUEUE,
                    device,
                    0,
                    streamState,
                    0);
        }
    
private voidsetSystemAudioMute(boolean state)

        if (mHdmiManager == null || mHdmiTvClient == null) return;
        synchronized (mHdmiManager) {
            if (!mHdmiSystemAudioSupported) return;
            synchronized (mHdmiTvClient) {
                final long token = Binder.clearCallingIdentity();
                try {
                    mHdmiTvClient.setSystemAudioMute(state);
                } finally {
                    Binder.restoreCallingIdentity(token);
                }
            }
        }
    
private voidsetSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags)

        if (mHdmiManager == null
                || mHdmiTvClient == null
                || oldVolume == newVolume
                || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0) return;

        // Sets the audio volume of AVR when we are in system audio mode. The new volume info
        // is tranformed to HDMI-CEC commands and passed through CEC bus.
        synchronized (mHdmiManager) {
            if (!mHdmiSystemAudioSupported) return;
            synchronized (mHdmiTvClient) {
                final long token = Binder.clearCallingIdentity();
                try {
                    mHdmiTvClient.setSystemAudioVolume(
                            (oldVolume + 5) / 10, (newVolume + 5) / 10, maxVolume);
                } finally {
                    Binder.restoreCallingIdentity(token);
                }
            }
        }
    
public voidsetVibrateSetting(int vibrateType, int vibrateSetting)

see
AudioManager#setVibrateSetting(int, int)


        if (!mHasVibrator) return;

        mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);

        // Broadcast change
        broadcastVibrateSetting(vibrateType);

    
public voidsetVolumeController(IVolumeController controller)

        enforceSelfOrSystemUI("set the volume controller");

        // return early if things are not actually changing
        if (mVolumeController.isSameBinder(controller)) {
            return;
        }

        // dismiss the old volume controller
        mVolumeController.postDismiss();
        if (controller != null) {
            // we are about to register a new controller, listen for its death
            try {
                controller.asBinder().linkToDeath(new DeathRecipient() {
                    @Override
                    public void binderDied() {
                        if (mVolumeController.isSameBinder(controller)) {
                            Log.w(TAG, "Current remote volume controller died, unregistering");
                            setVolumeController(null);
                        }
                    }
                }, 0);
            } catch (RemoteException e) {
                // noop
            }
        }
        mVolumeController.setController(controller);
        if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
    
public voidsetWiredDeviceConnectionState(int device, int state, java.lang.String name)

        synchronized (mConnectedDevices) {
            int delay = checkSendBecomingNoisyIntent(device, state);
            queueMsgUnderWakeLock(mAudioHandler,
                    MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
                    device,
                    state,
                    name,
                    delay);
        }
    
public booleanshouldVibrate(int vibrateType)

see
AudioManager#shouldVibrate(int)

        if (!mHasVibrator) return false;

        switch (getVibrateSetting(vibrateType)) {

            case AudioManager.VIBRATE_SETTING_ON:
                return getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT;

            case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
                return getRingerModeExternal() == AudioManager.RINGER_MODE_VIBRATE;

            case AudioManager.VIBRATE_SETTING_OFF:
                // return false, even for incoming calls
                return false;

            default:
                return false;
        }
    
public voidstartBluetoothSco(android.os.IBinder cb, int targetSdkVersion)

see
AudioManager#startBluetoothSco()

        int scoAudioMode =
                (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
                        SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
        startBluetoothScoInt(cb, scoAudioMode);
    
voidstartBluetoothScoInt(android.os.IBinder cb, int scoAudioMode)

        if (!checkAudioSettingsPermission("startBluetoothSco()") ||
                !mSystemReady) {
            return;
        }
        ScoClient client = getScoClient(cb, true);
        // The calling identity must be cleared before calling ScoClient.incCount().
        // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
        // and this must be done on behalf of system server to make sure permissions are granted.
        // The caller identity must be cleared after getScoClient() because it is needed if a new
        // client is created.
        final long ident = Binder.clearCallingIdentity();
        client.incCount(scoAudioMode);
        Binder.restoreCallingIdentity(ident);
    
public voidstartBluetoothScoVirtualCall(android.os.IBinder cb)

see
AudioManager#startBluetoothScoVirtualCall()

        startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
    
public AudioRoutesInfostartWatchingRoutes(IAudioRoutesObserver observer)

        synchronized (mCurAudioRoutes) {
            AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
            mRoutesObservers.register(observer);
            return routes;
        }
    
public voidstopBluetoothSco(android.os.IBinder cb)

see
AudioManager#stopBluetoothSco()

        if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
                !mSystemReady) {
            return;
        }
        ScoClient client = getScoClient(cb, false);
        // The calling identity must be cleared before calling ScoClient.decCount().
        // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
        // and this must be done on behalf of system server to make sure permissions are granted.
        final long ident = Binder.clearCallingIdentity();
        if (client != null) {
            client.decCount();
        }
        Binder.restoreCallingIdentity(ident);
    
public static java.lang.StringstreamToString(int stream)

hide

        if (stream >= 0 && stream < STREAM_NAMES.length) return STREAM_NAMES[stream];
        if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) return "USE_DEFAULT_STREAM_TYPE";
        return "UNKNOWN_STREAM_" + stream;
    
public voidsystemReady()

        sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
                0, 0, null, 0);
    
public voidunloadSoundEffects()
Unloads samples from the sound pool. This method can be called to free some memory when sound effects are disabled.

        sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
    
public voidunregisterAudioFocusClient(java.lang.String clientId)

        mMediaFocusControl.unregisterAudioFocusClient(clientId);
    
public voidunregisterAudioPolicyAsync(android.media.audiopolicy.IAudioPolicyCallback pcb)

        if (DEBUG_AP) Log.d(TAG, "unregisterAudioPolicyAsync for " + pcb.asBinder());
        synchronized (mAudioPolicies) {
            AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
            if (app == null) {
                Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
                        + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
                return;
            } else {
                pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
            }
            app.release();
        }
        // TODO implement clearing mix attribute matching info in native audio policy
    
public voidunregisterRemoteControlDisplay(IRemoteControlDisplay rcd)

        mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
    
private intupdateFlagsForSystemAudio(int flags)

        if (mHdmiTvClient != null) {
            synchronized (mHdmiTvClient) {
                if (mHdmiSystemAudioSupported &&
                        ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
                    flags &= ~AudioManager.FLAG_SHOW_UI;
                }
            }
        }
        return flags;
    
booleanupdateRingerModeAffectedStreams()

        int ringerModeAffectedStreams;
        // make sure settings for ringer mode are consistent with device type: non voice capable
        // devices (tablets) include media stream in silent mode whereas phones don't.
        ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
                Settings.System.MODE_RINGER_STREAMS_AFFECTED,
                ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
                 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
                 UserHandle.USER_CURRENT);

        // ringtone, notification and system streams are always affected by ringer mode
        ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
                                        (1 << AudioSystem.STREAM_NOTIFICATION)|
                                        (1 << AudioSystem.STREAM_SYSTEM);

        switch (mPlatformType) {
            case PLATFORM_TELEVISION:
                ringerModeAffectedStreams = 0;
                break;
            default:
                ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
                break;
        }

        synchronized (mCameraSoundForced) {
            if (mCameraSoundForced) {
                ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
            } else {
                ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
            }
        }
        if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
            ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
        } else {
            ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
        }

        if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
            Settings.System.putIntForUser(mContentResolver,
                    Settings.System.MODE_RINGER_STREAMS_AFFECTED,
                    ringerModeAffectedStreams,
                    UserHandle.USER_CURRENT);
            mRingerModeAffectedStreams = ringerModeAffectedStreams;
            return true;
        }
        return false;
    
private voidupdateStreamVolumeAlias(boolean updateVolumes)

        int dtmfStreamAlias;

        switch (mPlatformType) {
        case PLATFORM_VOICE:
            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
            dtmfStreamAlias = AudioSystem.STREAM_RING;
            break;
        case PLATFORM_TELEVISION:
            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
            dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
            break;
        default:
            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
            dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
        }

        if (isPlatformTelevision()) {
            mRingerModeAffectedStreams = 0;
        } else {
            if (isInCommunication()) {
                dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
                mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
            } else {
                mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
            }
        }

        mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
        if (updateVolumes) {
            mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
            // apply stream mute states according to new value of mRingerModeAffectedStreams
            setRingerModeInt(getRingerModeInternal(), false);
            sendMsg(mAudioHandler,
                    MSG_SET_ALL_VOLUMES,
                    SENDMSG_QUEUE,
                    0,
                    0,
                    mStreamStates[AudioSystem.STREAM_DTMF], 0);
        }
    
private voidwaitForAudioHandlerCreation()
Waits for the volume handler to be created by the other thread.

        synchronized(this) {
            while (mAudioHandler == null) {
                try {
                    // Wait for mAudioHandler to be set by the other thread
                    wait();
                } catch (InterruptedException e) {
                    Log.e(TAG, "Interrupted while waiting on volume handler.");
                }
            }
        }