Loading media/java/android/media/AudioService.java +286 −97 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.database.ContentObserver; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiPlaybackClient; import android.hardware.hdmi.HdmiTvClient; import android.hardware.usb.UsbManager; import android.media.MediaPlayer.OnCompletionListener; Loading Loading @@ -144,7 +145,23 @@ public class AudioService extends IAudioService.Stub { private final Context mContext; private final ContentResolver mContentResolver; private final AppOpsManager mAppOps; private final boolean mVoiceCapable; // the platform has no specific capabilities private static final int PLATFORM_DEFAULT = 0; // the platform is voice call capable (a phone) private static final int PLATFORM_VOICE = 1; // the platform is a television or a set-top box private static final int PLATFORM_TELEVISION = 2; // the platform type affects volume and silent mode behavior private final int mPlatformType; private boolean isPlatformVoice() { return mPlatformType == PLATFORM_VOICE; } private boolean isPlatformTelevision() { return mPlatformType == PLATFORM_TELEVISION; } /** The controller for the volume UI. */ private final VolumeController mVolumeController = new VolumeController(); Loading Loading @@ -243,9 +260,10 @@ public class AudioService extends IAudioService.Stub { * NOTE: do not create loops in aliases! * Some streams alias to different streams according to device category (phone or tablet) or * use case (in call vs off call...). See updateStreamVolumeAlias() for more details. * mStreamVolumeAlias contains the default aliases for a voice capable device (phone) and * STREAM_VOLUME_ALIAS_NON_VOICE for a non voice capable device (tablet).*/ private final int[] STREAM_VOLUME_ALIAS = new int[] { * mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device * (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and * STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/ private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] { AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL AudioSystem.STREAM_RING, // STREAM_SYSTEM AudioSystem.STREAM_RING, // STREAM_RING Loading @@ -257,7 +275,19 @@ public class AudioService extends IAudioService.Stub { AudioSystem.STREAM_RING, // STREAM_DTMF AudioSystem.STREAM_MUSIC // STREAM_TTS }; private final int[] STREAM_VOLUME_ALIAS_NON_VOICE = new int[] { private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] { AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM AudioSystem.STREAM_MUSIC, // STREAM_RING AudioSystem.STREAM_MUSIC, // STREAM_MUSIC AudioSystem.STREAM_MUSIC, // STREAM_ALARM AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED AudioSystem.STREAM_MUSIC, // STREAM_DTMF AudioSystem.STREAM_MUSIC // STREAM_TTS }; private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] { AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM AudioSystem.STREAM_RING, // STREAM_RING Loading Loading @@ -455,9 +485,12 @@ public class AudioService extends IAudioService.Stub { public final static int STREAM_REMOTE_MUSIC = -200; // Devices for which the volume is fixed and VolumePanel slider should be disabled final int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI | int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET | AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET; AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_HDMI_ARC | AudioSystem.DEVICE_OUT_SPDIF | AudioSystem.DEVICE_OUT_AUX_LINE; // TODO merge orientation and rotation private final boolean mMonitorOrientation; Loading Loading @@ -491,8 +524,16 @@ public class AudioService extends IAudioService.Stub { mContext = context; mContentResolver = context.getContentResolver(); mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); mVoiceCapable = mContext.getResources().getBoolean( com.android.internal.R.bool.config_voice_capable); if (mContext.getResources().getBoolean( com.android.internal.R.bool.config_voice_capable)) { mPlatformType = PLATFORM_VOICE; } else if (context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_TELEVISION)) { mPlatformType = PLATFORM_TELEVISION; } else { mPlatformType = PLATFORM_DEFAULT; } PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent"); Loading Loading @@ -622,10 +663,15 @@ public class AudioService extends IAudioService.Stub { BluetoothProfile.A2DP); } HdmiControlManager hdmiManager = mHdmiManager = (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE); // Null if device is not Tv. mHdmiTvClient = hdmiManager.getTvClient(); if (mHdmiManager != null) { synchronized (mHdmiManager) { mHdmiTvClient = mHdmiManager.getTvClient(); mHdmiPlaybackClient = mHdmiManager.getPlaybackClient(); mHdmiCecSink = false; } } sendMsg(mAudioHandler, MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED, Loading Loading @@ -670,6 +716,14 @@ public class AudioService extends IAudioService.Stub { } } private void checkAllFixedVolumeDevices() { int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int streamType = 0; streamType < numStreamTypes; streamType++) { mStreamStates[streamType].checkFixedVolumeDevices(); } } private void createStreamStates() { int numStreamTypes = AudioSystem.getNumStreamTypes(); VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes]; Loading @@ -678,6 +732,7 @@ public class AudioService extends IAudioService.Stub { streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i); } checkAllFixedVolumeDevices(); checkAllAliasStreamVolumes(); } Loading @@ -702,19 +757,32 @@ public class AudioService extends IAudioService.Stub { private void updateStreamVolumeAlias(boolean updateVolumes) { int dtmfStreamAlias; if (mVoiceCapable) { mStreamVolumeAlias = STREAM_VOLUME_ALIAS; switch (mPlatformType) { case PLATFORM_VOICE: mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE; dtmfStreamAlias = AudioSystem.STREAM_RING; } else { mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NON_VOICE; 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]); Loading Loading @@ -768,7 +836,7 @@ public class AudioService extends IAudioService.Stub { if (ringerMode != ringerModeFromSettings) { Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode); } if (mUseFixedVolume) { if (mUseFixedVolume || isPlatformTelevision()) { ringerMode = AudioManager.RINGER_MODE_NORMAL; } synchronized(mSettingsLock) { Loading Loading @@ -998,6 +1066,8 @@ public class AudioService extends IAudioService.Stub { // Check if volume update should be send to Hdmi system audio. int newIndex = mStreamStates[streamType].getIndex(device); if (mHdmiManager != null) { synchronized (mHdmiManager) { if (mHdmiTvClient != null && streamTypeAlias == AudioSystem.STREAM_MUSIC && (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 && Loading @@ -1010,6 +1080,19 @@ public class AudioService extends IAudioService.Stub { } } } // 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); Loading Loading @@ -1110,6 +1193,8 @@ public class AudioService extends IAudioService.Stub { } } if (mHdmiManager != null) { synchronized (mHdmiManager) { if (mHdmiTvClient != null && streamTypeAlias == AudioSystem.STREAM_MUSIC && (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 && Loading @@ -1122,6 +1207,8 @@ public class AudioService extends IAudioService.Stub { } } } } } flags &= ~AudioManager.FLAG_FIXED_VOLUME; if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) && Loading Loading @@ -1257,7 +1344,7 @@ public class AudioService extends IAudioService.Stub { // UI update and Broadcast Intent private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) { if (!mVoiceCapable && (streamType == AudioSystem.STREAM_RING)) { if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) { streamType = AudioSystem.STREAM_NOTIFICATION; } Loading Loading @@ -1346,6 +1433,8 @@ public class AudioService extends IAudioService.Stub { } if (isStreamAffectedByMute(streamType)) { if (mHdmiManager != null) { synchronized (mHdmiManager) { if (streamType == AudioSystem.STREAM_MUSIC && mHdmiTvClient != null) { synchronized (mHdmiTvClient) { if (mHdmiSystemAudioSupported) { Loading @@ -1353,6 +1442,8 @@ public class AudioService extends IAudioService.Stub { } } } } } mStreamStates[streamType].mute(cb, state); } } Loading Loading @@ -1472,11 +1563,15 @@ public class AudioService extends IAudioService.Stub { /** @see AudioManager#getMasterStreamType() */ public int getMasterStreamType() { if (mVoiceCapable) { switch (mPlatformType) { case PLATFORM_VOICE: return AudioSystem.STREAM_RING; } else { return AudioSystem.STREAM_NOTIFICATION; case PLATFORM_TELEVISION: return AudioSystem.STREAM_MUSIC; default: break; } return AudioSystem.STREAM_NOTIFICATION; } /** @see AudioManager#setMicrophoneMute(boolean) */ Loading Loading @@ -1504,7 +1599,7 @@ public class AudioService extends IAudioService.Stub { /** @see AudioManager#setRingerMode(int) */ public void setRingerMode(int ringerMode) { if (mUseFixedVolume) { if (mUseFixedVolume || isPlatformTelevision()) { return; } Loading Loading @@ -1534,7 +1629,7 @@ public class AudioService extends IAudioService.Stub { ringerMode == AudioManager.RINGER_MODE_NORMAL) { // ring and notifications volume should never be 0 when not silenced // on voice capable devices if (mVoiceCapable && if (isPlatformVoice() && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) { synchronized (mStreamStates[streamType]) { Set set = mStreamStates[streamType].mIndex.entrySet(); Loading Loading @@ -2041,6 +2136,7 @@ public class AudioService extends IAudioService.Stub { // muted by ringer mode have the correct volume setRingerModeInt(getRingerMode(), false); checkAllFixedVolumeDevices(); checkAllAliasStreamVolumes(); synchronized (mSafeMediaVolumeState) { Loading Loading @@ -2760,11 +2856,18 @@ public class AudioService extends IAudioService.Stub { (1 << AudioSystem.STREAM_NOTIFICATION)| (1 << AudioSystem.STREAM_SYSTEM); if (mVoiceCapable) { switch (mPlatformType) { case PLATFORM_VOICE: ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC); } else { break; case PLATFORM_TELEVISION: ringerModeAffectedStreams = 0; break; default: ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC); break; } synchronized (mCameraSoundForced) { if (mCameraSoundForced) { ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED); Loading Loading @@ -2833,7 +2936,8 @@ public class AudioService extends IAudioService.Stub { } private int getActiveStreamType(int suggestedStreamType) { if (mVoiceCapable) { switch (mPlatformType) { case PLATFORM_VOICE: if (isInCommunication()) { if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) == AudioSystem.FORCE_BT_SCO) { Loading Loading @@ -2863,12 +2967,26 @@ public class AudioService extends IAudioService.Stub { if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active"); return AudioSystem.STREAM_MUSIC; } else { if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type " + suggestedStreamType); return suggestedStreamType; } break; case PLATFORM_TELEVISION: if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) { if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC"); return AudioSystem.STREAM_MUSIC; } else if (mMediaFocusControl.checkUpdateRemoteStateIfActive( AudioSystem.STREAM_MUSIC)) { if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC"); return STREAM_REMOTE_MUSIC; } else { if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: using STREAM_MUSIC as default"); return AudioSystem.STREAM_MUSIC; } } break; default: if (isInCommunication()) { if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) == AudioSystem.FORCE_BT_SCO) { Loading Loading @@ -2899,13 +3017,13 @@ public class AudioService extends IAudioService.Stub { "getActiveStreamType: using STREAM_NOTIFICATION as default"); return AudioSystem.STREAM_NOTIFICATION; } } else { } break; } if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type " + suggestedStreamType); return suggestedStreamType; } } } private void broadcastRingerMode(int ringerMode) { // Send sticky broadcast Loading Loading @@ -3098,16 +3216,10 @@ public class AudioService extends IAudioService.Stub { continue; } // ignore settings for fixed volume devices: volume should always be at max or 0 if ((mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) && ((device & mFixedVolumeDevices) != 0)) { mIndex.put(device, (index != 0) ? mIndexMax : 0); } else { mIndex.put(device, getValidIndex(10 * index)); } } } } public void applyDeviceVolume(int device) { int index; Loading Loading @@ -3263,6 +3375,25 @@ public class AudioService extends IAudioService.Stub { return mStreamType; } public void checkFixedVolumeDevices() { synchronized (VolumeStreamState.class) { // ignore settings for fixed volume devices: volume should always be at max or 0 if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) { Set set = mIndex.entrySet(); Iterator i = set.iterator(); while (i.hasNext()) { Map.Entry entry = (Map.Entry)i.next(); int device = ((Integer)entry.getKey()).intValue(); int index = ((Integer)entry.getValue()).intValue(); if (((device & mFixedVolumeDevices) != 0) && index != 0) { entry.setValue(mIndexMax); } applyDeviceVolume(device); } } } } private int getValidIndex(int index) { if (index < 0) { return 0; Loading Loading @@ -3469,6 +3600,9 @@ public class AudioService extends IAudioService.Stub { if (mUseFixedVolume) { return; } if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) { return; } System.putIntForUser(mContentResolver, streamState.getSettingNameForDevice(device), (streamState.getIndex(device) + 5)/ 10, Loading Loading @@ -3825,11 +3959,13 @@ public class AudioService extends IAudioService.Stub { mDockAudioMediaEnabled ? AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE); } if (mHdmiManager != null) { synchronized (mHdmiManager) { if (mHdmiTvClient != null) { setHdmiSystemAudioSupported(mHdmiSystemAudioSupported); } } } // indicate the end of reconfiguration phase to audio HAL AudioSystem.setParameters("restarting=false"); break; Loading Loading @@ -4275,6 +4411,27 @@ public class AudioService extends IAudioService.Stub { 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); Loading Loading @@ -4577,6 +4734,7 @@ public class AudioService extends IAudioService.Stub { if (cameraSoundForced != mCameraSoundForced) { mCameraSoundForced = cameraSoundForced; if (!isPlatformTelevision()) { VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED]; if (cameraSoundForced) { s.setAllIndexesToMax(); Loading @@ -4589,6 +4747,7 @@ public class AudioService extends IAudioService.Stub { } // take new state into account for streams muted by ringer mode setRingerModeInt(getRingerMode(), false); } sendMsg(mAudioHandler, MSG_SET_FORCE_USE, Loading Loading @@ -4804,27 +4963,57 @@ public class AudioService extends IAudioService.Stub { // to HdmiControlService so that audio recevier can handle volume change. //========================================================================================== private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback { public void onComplete(int status) { if (mHdmiManager != null) { synchronized (mHdmiManager) { mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN); // Television devices without CEC service apply software volume on HDMI output if (isPlatformTelevision() && !mHdmiCecSink) { mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI; } checkAllFixedVolumeDevices(); } } } }; // If HDMI-CEC system audio is supported private boolean mHdmiSystemAudioSupported = false; // Set only when device is tv. private HdmiTvClient mHdmiTvClient; // true if the device has system feature PackageManager.FEATURE_TELEVISION. // cached HdmiControlManager interface private HdmiControlManager mHdmiManager; // Set only when device is a set-top box. private HdmiPlaybackClient mHdmiPlaybackClient; // true if we are a set-top box, an HDMI sink is connected and it supports CEC. private boolean mHdmiCecSink; private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback(); @Override public int setHdmiSystemAudioSupported(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 AudioSystem.DEVICE_NONE; return device; } synchronized (mHdmiTvClient) { if (mHdmiSystemAudioSupported == on) { return AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC); } if (mHdmiSystemAudioSupported != on) { mHdmiSystemAudioSupported = on; AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO, on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED : AudioSystem.FORCE_NONE); on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED : AudioSystem.FORCE_NONE); } device = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC); } return AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC); } } return device; } //========================================================================================== Loading Loading
media/java/android/media/AudioService.java +286 −97 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.database.ContentObserver; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiPlaybackClient; import android.hardware.hdmi.HdmiTvClient; import android.hardware.usb.UsbManager; import android.media.MediaPlayer.OnCompletionListener; Loading Loading @@ -144,7 +145,23 @@ public class AudioService extends IAudioService.Stub { private final Context mContext; private final ContentResolver mContentResolver; private final AppOpsManager mAppOps; private final boolean mVoiceCapable; // the platform has no specific capabilities private static final int PLATFORM_DEFAULT = 0; // the platform is voice call capable (a phone) private static final int PLATFORM_VOICE = 1; // the platform is a television or a set-top box private static final int PLATFORM_TELEVISION = 2; // the platform type affects volume and silent mode behavior private final int mPlatformType; private boolean isPlatformVoice() { return mPlatformType == PLATFORM_VOICE; } private boolean isPlatformTelevision() { return mPlatformType == PLATFORM_TELEVISION; } /** The controller for the volume UI. */ private final VolumeController mVolumeController = new VolumeController(); Loading Loading @@ -243,9 +260,10 @@ public class AudioService extends IAudioService.Stub { * NOTE: do not create loops in aliases! * Some streams alias to different streams according to device category (phone or tablet) or * use case (in call vs off call...). See updateStreamVolumeAlias() for more details. * mStreamVolumeAlias contains the default aliases for a voice capable device (phone) and * STREAM_VOLUME_ALIAS_NON_VOICE for a non voice capable device (tablet).*/ private final int[] STREAM_VOLUME_ALIAS = new int[] { * mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device * (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and * STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/ private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] { AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL AudioSystem.STREAM_RING, // STREAM_SYSTEM AudioSystem.STREAM_RING, // STREAM_RING Loading @@ -257,7 +275,19 @@ public class AudioService extends IAudioService.Stub { AudioSystem.STREAM_RING, // STREAM_DTMF AudioSystem.STREAM_MUSIC // STREAM_TTS }; private final int[] STREAM_VOLUME_ALIAS_NON_VOICE = new int[] { private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] { AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM AudioSystem.STREAM_MUSIC, // STREAM_RING AudioSystem.STREAM_MUSIC, // STREAM_MUSIC AudioSystem.STREAM_MUSIC, // STREAM_ALARM AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED AudioSystem.STREAM_MUSIC, // STREAM_DTMF AudioSystem.STREAM_MUSIC // STREAM_TTS }; private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] { AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM AudioSystem.STREAM_RING, // STREAM_RING Loading Loading @@ -455,9 +485,12 @@ public class AudioService extends IAudioService.Stub { public final static int STREAM_REMOTE_MUSIC = -200; // Devices for which the volume is fixed and VolumePanel slider should be disabled final int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI | int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET | AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET; AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_HDMI_ARC | AudioSystem.DEVICE_OUT_SPDIF | AudioSystem.DEVICE_OUT_AUX_LINE; // TODO merge orientation and rotation private final boolean mMonitorOrientation; Loading Loading @@ -491,8 +524,16 @@ public class AudioService extends IAudioService.Stub { mContext = context; mContentResolver = context.getContentResolver(); mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); mVoiceCapable = mContext.getResources().getBoolean( com.android.internal.R.bool.config_voice_capable); if (mContext.getResources().getBoolean( com.android.internal.R.bool.config_voice_capable)) { mPlatformType = PLATFORM_VOICE; } else if (context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_TELEVISION)) { mPlatformType = PLATFORM_TELEVISION; } else { mPlatformType = PLATFORM_DEFAULT; } PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent"); Loading Loading @@ -622,10 +663,15 @@ public class AudioService extends IAudioService.Stub { BluetoothProfile.A2DP); } HdmiControlManager hdmiManager = mHdmiManager = (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE); // Null if device is not Tv. mHdmiTvClient = hdmiManager.getTvClient(); if (mHdmiManager != null) { synchronized (mHdmiManager) { mHdmiTvClient = mHdmiManager.getTvClient(); mHdmiPlaybackClient = mHdmiManager.getPlaybackClient(); mHdmiCecSink = false; } } sendMsg(mAudioHandler, MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED, Loading Loading @@ -670,6 +716,14 @@ public class AudioService extends IAudioService.Stub { } } private void checkAllFixedVolumeDevices() { int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int streamType = 0; streamType < numStreamTypes; streamType++) { mStreamStates[streamType].checkFixedVolumeDevices(); } } private void createStreamStates() { int numStreamTypes = AudioSystem.getNumStreamTypes(); VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes]; Loading @@ -678,6 +732,7 @@ public class AudioService extends IAudioService.Stub { streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i); } checkAllFixedVolumeDevices(); checkAllAliasStreamVolumes(); } Loading @@ -702,19 +757,32 @@ public class AudioService extends IAudioService.Stub { private void updateStreamVolumeAlias(boolean updateVolumes) { int dtmfStreamAlias; if (mVoiceCapable) { mStreamVolumeAlias = STREAM_VOLUME_ALIAS; switch (mPlatformType) { case PLATFORM_VOICE: mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE; dtmfStreamAlias = AudioSystem.STREAM_RING; } else { mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NON_VOICE; 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]); Loading Loading @@ -768,7 +836,7 @@ public class AudioService extends IAudioService.Stub { if (ringerMode != ringerModeFromSettings) { Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode); } if (mUseFixedVolume) { if (mUseFixedVolume || isPlatformTelevision()) { ringerMode = AudioManager.RINGER_MODE_NORMAL; } synchronized(mSettingsLock) { Loading Loading @@ -998,6 +1066,8 @@ public class AudioService extends IAudioService.Stub { // Check if volume update should be send to Hdmi system audio. int newIndex = mStreamStates[streamType].getIndex(device); if (mHdmiManager != null) { synchronized (mHdmiManager) { if (mHdmiTvClient != null && streamTypeAlias == AudioSystem.STREAM_MUSIC && (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 && Loading @@ -1010,6 +1080,19 @@ public class AudioService extends IAudioService.Stub { } } } // 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); Loading Loading @@ -1110,6 +1193,8 @@ public class AudioService extends IAudioService.Stub { } } if (mHdmiManager != null) { synchronized (mHdmiManager) { if (mHdmiTvClient != null && streamTypeAlias == AudioSystem.STREAM_MUSIC && (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 && Loading @@ -1122,6 +1207,8 @@ public class AudioService extends IAudioService.Stub { } } } } } flags &= ~AudioManager.FLAG_FIXED_VOLUME; if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) && Loading Loading @@ -1257,7 +1344,7 @@ public class AudioService extends IAudioService.Stub { // UI update and Broadcast Intent private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) { if (!mVoiceCapable && (streamType == AudioSystem.STREAM_RING)) { if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) { streamType = AudioSystem.STREAM_NOTIFICATION; } Loading Loading @@ -1346,6 +1433,8 @@ public class AudioService extends IAudioService.Stub { } if (isStreamAffectedByMute(streamType)) { if (mHdmiManager != null) { synchronized (mHdmiManager) { if (streamType == AudioSystem.STREAM_MUSIC && mHdmiTvClient != null) { synchronized (mHdmiTvClient) { if (mHdmiSystemAudioSupported) { Loading @@ -1353,6 +1442,8 @@ public class AudioService extends IAudioService.Stub { } } } } } mStreamStates[streamType].mute(cb, state); } } Loading Loading @@ -1472,11 +1563,15 @@ public class AudioService extends IAudioService.Stub { /** @see AudioManager#getMasterStreamType() */ public int getMasterStreamType() { if (mVoiceCapable) { switch (mPlatformType) { case PLATFORM_VOICE: return AudioSystem.STREAM_RING; } else { return AudioSystem.STREAM_NOTIFICATION; case PLATFORM_TELEVISION: return AudioSystem.STREAM_MUSIC; default: break; } return AudioSystem.STREAM_NOTIFICATION; } /** @see AudioManager#setMicrophoneMute(boolean) */ Loading Loading @@ -1504,7 +1599,7 @@ public class AudioService extends IAudioService.Stub { /** @see AudioManager#setRingerMode(int) */ public void setRingerMode(int ringerMode) { if (mUseFixedVolume) { if (mUseFixedVolume || isPlatformTelevision()) { return; } Loading Loading @@ -1534,7 +1629,7 @@ public class AudioService extends IAudioService.Stub { ringerMode == AudioManager.RINGER_MODE_NORMAL) { // ring and notifications volume should never be 0 when not silenced // on voice capable devices if (mVoiceCapable && if (isPlatformVoice() && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) { synchronized (mStreamStates[streamType]) { Set set = mStreamStates[streamType].mIndex.entrySet(); Loading Loading @@ -2041,6 +2136,7 @@ public class AudioService extends IAudioService.Stub { // muted by ringer mode have the correct volume setRingerModeInt(getRingerMode(), false); checkAllFixedVolumeDevices(); checkAllAliasStreamVolumes(); synchronized (mSafeMediaVolumeState) { Loading Loading @@ -2760,11 +2856,18 @@ public class AudioService extends IAudioService.Stub { (1 << AudioSystem.STREAM_NOTIFICATION)| (1 << AudioSystem.STREAM_SYSTEM); if (mVoiceCapable) { switch (mPlatformType) { case PLATFORM_VOICE: ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC); } else { break; case PLATFORM_TELEVISION: ringerModeAffectedStreams = 0; break; default: ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC); break; } synchronized (mCameraSoundForced) { if (mCameraSoundForced) { ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED); Loading Loading @@ -2833,7 +2936,8 @@ public class AudioService extends IAudioService.Stub { } private int getActiveStreamType(int suggestedStreamType) { if (mVoiceCapable) { switch (mPlatformType) { case PLATFORM_VOICE: if (isInCommunication()) { if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) == AudioSystem.FORCE_BT_SCO) { Loading Loading @@ -2863,12 +2967,26 @@ public class AudioService extends IAudioService.Stub { if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active"); return AudioSystem.STREAM_MUSIC; } else { if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type " + suggestedStreamType); return suggestedStreamType; } break; case PLATFORM_TELEVISION: if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) { if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC"); return AudioSystem.STREAM_MUSIC; } else if (mMediaFocusControl.checkUpdateRemoteStateIfActive( AudioSystem.STREAM_MUSIC)) { if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC"); return STREAM_REMOTE_MUSIC; } else { if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: using STREAM_MUSIC as default"); return AudioSystem.STREAM_MUSIC; } } break; default: if (isInCommunication()) { if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) == AudioSystem.FORCE_BT_SCO) { Loading Loading @@ -2899,13 +3017,13 @@ public class AudioService extends IAudioService.Stub { "getActiveStreamType: using STREAM_NOTIFICATION as default"); return AudioSystem.STREAM_NOTIFICATION; } } else { } break; } if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type " + suggestedStreamType); return suggestedStreamType; } } } private void broadcastRingerMode(int ringerMode) { // Send sticky broadcast Loading Loading @@ -3098,16 +3216,10 @@ public class AudioService extends IAudioService.Stub { continue; } // ignore settings for fixed volume devices: volume should always be at max or 0 if ((mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) && ((device & mFixedVolumeDevices) != 0)) { mIndex.put(device, (index != 0) ? mIndexMax : 0); } else { mIndex.put(device, getValidIndex(10 * index)); } } } } public void applyDeviceVolume(int device) { int index; Loading Loading @@ -3263,6 +3375,25 @@ public class AudioService extends IAudioService.Stub { return mStreamType; } public void checkFixedVolumeDevices() { synchronized (VolumeStreamState.class) { // ignore settings for fixed volume devices: volume should always be at max or 0 if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) { Set set = mIndex.entrySet(); Iterator i = set.iterator(); while (i.hasNext()) { Map.Entry entry = (Map.Entry)i.next(); int device = ((Integer)entry.getKey()).intValue(); int index = ((Integer)entry.getValue()).intValue(); if (((device & mFixedVolumeDevices) != 0) && index != 0) { entry.setValue(mIndexMax); } applyDeviceVolume(device); } } } } private int getValidIndex(int index) { if (index < 0) { return 0; Loading Loading @@ -3469,6 +3600,9 @@ public class AudioService extends IAudioService.Stub { if (mUseFixedVolume) { return; } if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) { return; } System.putIntForUser(mContentResolver, streamState.getSettingNameForDevice(device), (streamState.getIndex(device) + 5)/ 10, Loading Loading @@ -3825,11 +3959,13 @@ public class AudioService extends IAudioService.Stub { mDockAudioMediaEnabled ? AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE); } if (mHdmiManager != null) { synchronized (mHdmiManager) { if (mHdmiTvClient != null) { setHdmiSystemAudioSupported(mHdmiSystemAudioSupported); } } } // indicate the end of reconfiguration phase to audio HAL AudioSystem.setParameters("restarting=false"); break; Loading Loading @@ -4275,6 +4411,27 @@ public class AudioService extends IAudioService.Stub { 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); Loading Loading @@ -4577,6 +4734,7 @@ public class AudioService extends IAudioService.Stub { if (cameraSoundForced != mCameraSoundForced) { mCameraSoundForced = cameraSoundForced; if (!isPlatformTelevision()) { VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED]; if (cameraSoundForced) { s.setAllIndexesToMax(); Loading @@ -4589,6 +4747,7 @@ public class AudioService extends IAudioService.Stub { } // take new state into account for streams muted by ringer mode setRingerModeInt(getRingerMode(), false); } sendMsg(mAudioHandler, MSG_SET_FORCE_USE, Loading Loading @@ -4804,27 +4963,57 @@ public class AudioService extends IAudioService.Stub { // to HdmiControlService so that audio recevier can handle volume change. //========================================================================================== private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback { public void onComplete(int status) { if (mHdmiManager != null) { synchronized (mHdmiManager) { mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN); // Television devices without CEC service apply software volume on HDMI output if (isPlatformTelevision() && !mHdmiCecSink) { mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI; } checkAllFixedVolumeDevices(); } } } }; // If HDMI-CEC system audio is supported private boolean mHdmiSystemAudioSupported = false; // Set only when device is tv. private HdmiTvClient mHdmiTvClient; // true if the device has system feature PackageManager.FEATURE_TELEVISION. // cached HdmiControlManager interface private HdmiControlManager mHdmiManager; // Set only when device is a set-top box. private HdmiPlaybackClient mHdmiPlaybackClient; // true if we are a set-top box, an HDMI sink is connected and it supports CEC. private boolean mHdmiCecSink; private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback(); @Override public int setHdmiSystemAudioSupported(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 AudioSystem.DEVICE_NONE; return device; } synchronized (mHdmiTvClient) { if (mHdmiSystemAudioSupported == on) { return AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC); } if (mHdmiSystemAudioSupported != on) { mHdmiSystemAudioSupported = on; AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO, on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED : AudioSystem.FORCE_NONE); on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED : AudioSystem.FORCE_NONE); } device = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC); } return AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC); } } return device; } //========================================================================================== Loading