Loading services/core/java/com/android/server/audio/AudioDeviceBroker.java +49 −0 Original line number Diff line number Diff line Loading @@ -45,7 +45,10 @@ import com.android.internal.annotations.GuardedBy; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashSet; import java.util.NoSuchElementException; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; /** @hide */ Loading @@ -59,6 +62,9 @@ import java.util.NoSuchElementException; // Timeout for connection to bluetooth headset service /*package*/ static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000; // Delay before checking it music should be unmuted after processing an A2DP message private static final int BTA2DP_MUTE_CHECK_DELAY_MS = 50; private final @NonNull AudioService mAudioService; private final @NonNull Context mContext; Loading Loading @@ -1050,9 +1056,19 @@ import java.util.NoSuchElementException; final int strategy = msg.arg1; mDeviceInventory.onSaveRemovePreferredDevice(strategy); } break; case MSG_CHECK_MUTE_MUSIC: checkMessagesMuteMusic(); break; default: Log.wtf(TAG, "Invalid message " + msg.what); } // Give some time to Bluetooth service to post a connection message // in case of active device switch if (MESSAGES_MUTE_MUSIC.contains(msg.what)) { sendMsg(MSG_CHECK_MUTE_MUSIC, SENDMSG_REPLACE, BTA2DP_MUTE_CHECK_DELAY_MS); } if (isMessageHandledUnderWakelock(msg.what)) { try { mBrokerEventWakeLock.release(); Loading Loading @@ -1116,6 +1132,7 @@ import java.util.NoSuchElementException; private static final int MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY = 34; private static final int MSG_L_SPEAKERPHONE_CLIENT_DIED = 35; private static final int MSG_CHECK_MUTE_MUSIC = 36; private static boolean isMessageHandledUnderWakelock(int msgId) { Loading @@ -1132,6 +1149,7 @@ import java.util.NoSuchElementException; case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION: case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION: case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT: case MSG_CHECK_MUTE_MUSIC: return true; default: return false; Loading Loading @@ -1231,6 +1249,37 @@ import java.util.NoSuchElementException; mBrokerHandler.sendMessageAtTime(mBrokerHandler.obtainMessage(msg, arg1, arg2, obj), time); } if (MESSAGES_MUTE_MUSIC.contains(msg)) { checkMessagesMuteMusic(); } } /** List of messages for which music is muted while processing is pending */ private static final Set<Integer> MESSAGES_MUTE_MUSIC; static { MESSAGES_MUTE_MUSIC = new HashSet<>(); MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED); MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED); MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONFIG_CHANGE); MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE); MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION); MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION); } private AtomicBoolean mMusicMuted = new AtomicBoolean(false); /** Mutes or unmutes music according to pending A2DP messages */ private void checkMessagesMuteMusic() { boolean mute = false; for (int msg : MESSAGES_MUTE_MUSIC) { if (mBrokerHandler.hasMessages(msg)) { mute = true; break; } } if (mute != mMusicMuted.getAndSet(mute)) { mAudioService.setMusicMute(mute); } } private class SpeakerphoneClient implements IBinder.DeathRecipient { Loading services/core/java/com/android/server/audio/AudioService.java +47 −4 Original line number Diff line number Diff line Loading @@ -5061,6 +5061,10 @@ public class AudioService extends IAudioService.Stub profile, suppressNoisyIntent, a2dpVolume); } /*package*/ void setMusicMute(boolean mute) { mStreamStates[AudioSystem.STREAM_MUSIC].muteInternally(mute); } /** * See AudioManager.handleBluetoothA2dpDeviceConfigChange() * @param device Loading Loading @@ -5463,6 +5467,7 @@ public class AudioService extends IAudioService.Stub private int mIndexMax; private boolean mIsMuted; private boolean mIsMutedInternally; private String mVolumeIndexSettingName; private int mObservedDevices; Loading Loading @@ -5636,7 +5641,8 @@ public class AudioService extends IAudioService.Stub // Only set audio policy BT SCO stream volume to 0 when the stream is actually muted. // This allows RX path muting by the audio HAL only when explicitly muted but not when // index is just set to 0 to repect BT requirements if (mStreamType == AudioSystem.STREAM_BLUETOOTH_SCO && index == 0 && !mIsMuted) { if (mStreamType == AudioSystem.STREAM_BLUETOOTH_SCO && index == 0 && !isFullyMuted()) { index = 1; } AudioSystem.setStreamVolumeIndexAS(mStreamType, index, device); Loading @@ -5645,7 +5651,7 @@ public class AudioService extends IAudioService.Stub // must be called while synchronized VolumeStreamState.class /*package*/ void applyDeviceVolume_syncVSS(int device, boolean isAvrcpAbsVolSupported) { int index; if (mIsMuted) { if (isFullyMuted()) { index = 0; } else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device) && isAvrcpAbsVolSupported) { Loading @@ -5668,7 +5674,7 @@ public class AudioService extends IAudioService.Stub for (int i = 0; i < mIndexMap.size(); i++) { final int device = mIndexMap.keyAt(i); if (device != AudioSystem.DEVICE_OUT_DEFAULT) { if (mIsMuted) { if (isFullyMuted()) { index = 0; } else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device) && isAvrcpAbsVolSupported) { Loading @@ -5685,7 +5691,7 @@ public class AudioService extends IAudioService.Stub } // apply default volume last: by convention , default device volume will be used // by audio policy manager if no explicit volume is present for a given device type if (mIsMuted) { if (isFullyMuted()) { index = 0; } else { index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10; Loading Loading @@ -5867,6 +5873,41 @@ public class AudioService extends IAudioService.Stub return changed; } /** * Mute/unmute the stream by AudioService * @param state the new mute state * @return true if the mute state was changed */ public boolean muteInternally(boolean state) { boolean changed = false; synchronized (VolumeStreamState.class) { if (state != mIsMutedInternally) { changed = true; mIsMutedInternally = state; // Set the new mute volume. This propagates the values to // the audio system, otherwise the volume won't be changed // at the lower level. sendMsg(mAudioHandler, MSG_SET_ALL_VOLUMES, SENDMSG_QUEUE, 0, 0, this, 0); } } if (changed) { sVolumeLogger.log(new VolumeEvent( VolumeEvent.VOL_MUTE_STREAM_INT, mStreamType, state)); } return changed; } @GuardedBy("VolumeStreamState.class") public boolean isFullyMuted() { return mIsMuted || mIsMutedInternally; } public int getStreamType() { return mStreamType; } Loading Loading @@ -5903,6 +5944,8 @@ public class AudioService extends IAudioService.Stub private void dump(PrintWriter pw) { pw.print(" Muted: "); pw.println(mIsMuted); pw.print(" Muted Internally: "); pw.println(mIsMutedInternally); pw.print(" Min: "); pw.print((mIndexMin + 5) / 10); if (mIndexMin != mIndexMinNoPerm) { Loading services/core/java/com/android/server/audio/AudioServiceEvents.java +21 −0 Original line number Diff line number Diff line Loading @@ -100,6 +100,7 @@ public class AudioServiceEvents { static final int VOL_VOICE_ACTIVITY_HEARING_AID = 6; static final int VOL_MODE_CHANGE_HEARING_AID = 7; static final int VOL_SET_GROUP_VOL = 8; static final int VOL_MUTE_STREAM_INT = 9; final int mOp; final int mStream; Loading Loading @@ -188,6 +189,18 @@ public class AudioServiceEvents { logMetricEvent(); } /** used for VOL_MUTE_STREAM_INT */ VolumeEvent(int op, int stream, boolean state) { mOp = op; mStream = stream; mVal1 = state ? 1 : 0; mVal2 = 0; mCaller = null; mGroupName = null; mAudioAttributes = null; logMetricEvent(); } /** * Audio Analytics unique Id. Loading Loading @@ -278,6 +291,9 @@ public class AudioServiceEvents { .set(MediaMetrics.Property.INDEX, mVal1) .record(); return; case VOL_MUTE_STREAM_INT: // No value in logging metrics for this internal event return; default: return; } Loading Loading @@ -343,6 +359,11 @@ public class AudioServiceEvents { .append(" flags:0x").append(Integer.toHexString(mVal2)) .append(") from ").append(mCaller) .toString(); case VOL_MUTE_STREAM_INT: return new StringBuilder("VolumeStreamState.muteInternally(stream:") .append(AudioSystem.streamToString(mStream)) .append(mVal1 == 1 ? ", muted)" : ", unmuted)") .toString(); default: return new StringBuilder("FIXME invalid op:").append(mOp).toString(); } } Loading Loading
services/core/java/com/android/server/audio/AudioDeviceBroker.java +49 −0 Original line number Diff line number Diff line Loading @@ -45,7 +45,10 @@ import com.android.internal.annotations.GuardedBy; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashSet; import java.util.NoSuchElementException; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; /** @hide */ Loading @@ -59,6 +62,9 @@ import java.util.NoSuchElementException; // Timeout for connection to bluetooth headset service /*package*/ static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000; // Delay before checking it music should be unmuted after processing an A2DP message private static final int BTA2DP_MUTE_CHECK_DELAY_MS = 50; private final @NonNull AudioService mAudioService; private final @NonNull Context mContext; Loading Loading @@ -1050,9 +1056,19 @@ import java.util.NoSuchElementException; final int strategy = msg.arg1; mDeviceInventory.onSaveRemovePreferredDevice(strategy); } break; case MSG_CHECK_MUTE_MUSIC: checkMessagesMuteMusic(); break; default: Log.wtf(TAG, "Invalid message " + msg.what); } // Give some time to Bluetooth service to post a connection message // in case of active device switch if (MESSAGES_MUTE_MUSIC.contains(msg.what)) { sendMsg(MSG_CHECK_MUTE_MUSIC, SENDMSG_REPLACE, BTA2DP_MUTE_CHECK_DELAY_MS); } if (isMessageHandledUnderWakelock(msg.what)) { try { mBrokerEventWakeLock.release(); Loading Loading @@ -1116,6 +1132,7 @@ import java.util.NoSuchElementException; private static final int MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY = 34; private static final int MSG_L_SPEAKERPHONE_CLIENT_DIED = 35; private static final int MSG_CHECK_MUTE_MUSIC = 36; private static boolean isMessageHandledUnderWakelock(int msgId) { Loading @@ -1132,6 +1149,7 @@ import java.util.NoSuchElementException; case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION: case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION: case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT: case MSG_CHECK_MUTE_MUSIC: return true; default: return false; Loading Loading @@ -1231,6 +1249,37 @@ import java.util.NoSuchElementException; mBrokerHandler.sendMessageAtTime(mBrokerHandler.obtainMessage(msg, arg1, arg2, obj), time); } if (MESSAGES_MUTE_MUSIC.contains(msg)) { checkMessagesMuteMusic(); } } /** List of messages for which music is muted while processing is pending */ private static final Set<Integer> MESSAGES_MUTE_MUSIC; static { MESSAGES_MUTE_MUSIC = new HashSet<>(); MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED); MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED); MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONFIG_CHANGE); MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE); MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION); MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION); } private AtomicBoolean mMusicMuted = new AtomicBoolean(false); /** Mutes or unmutes music according to pending A2DP messages */ private void checkMessagesMuteMusic() { boolean mute = false; for (int msg : MESSAGES_MUTE_MUSIC) { if (mBrokerHandler.hasMessages(msg)) { mute = true; break; } } if (mute != mMusicMuted.getAndSet(mute)) { mAudioService.setMusicMute(mute); } } private class SpeakerphoneClient implements IBinder.DeathRecipient { Loading
services/core/java/com/android/server/audio/AudioService.java +47 −4 Original line number Diff line number Diff line Loading @@ -5061,6 +5061,10 @@ public class AudioService extends IAudioService.Stub profile, suppressNoisyIntent, a2dpVolume); } /*package*/ void setMusicMute(boolean mute) { mStreamStates[AudioSystem.STREAM_MUSIC].muteInternally(mute); } /** * See AudioManager.handleBluetoothA2dpDeviceConfigChange() * @param device Loading Loading @@ -5463,6 +5467,7 @@ public class AudioService extends IAudioService.Stub private int mIndexMax; private boolean mIsMuted; private boolean mIsMutedInternally; private String mVolumeIndexSettingName; private int mObservedDevices; Loading Loading @@ -5636,7 +5641,8 @@ public class AudioService extends IAudioService.Stub // Only set audio policy BT SCO stream volume to 0 when the stream is actually muted. // This allows RX path muting by the audio HAL only when explicitly muted but not when // index is just set to 0 to repect BT requirements if (mStreamType == AudioSystem.STREAM_BLUETOOTH_SCO && index == 0 && !mIsMuted) { if (mStreamType == AudioSystem.STREAM_BLUETOOTH_SCO && index == 0 && !isFullyMuted()) { index = 1; } AudioSystem.setStreamVolumeIndexAS(mStreamType, index, device); Loading @@ -5645,7 +5651,7 @@ public class AudioService extends IAudioService.Stub // must be called while synchronized VolumeStreamState.class /*package*/ void applyDeviceVolume_syncVSS(int device, boolean isAvrcpAbsVolSupported) { int index; if (mIsMuted) { if (isFullyMuted()) { index = 0; } else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device) && isAvrcpAbsVolSupported) { Loading @@ -5668,7 +5674,7 @@ public class AudioService extends IAudioService.Stub for (int i = 0; i < mIndexMap.size(); i++) { final int device = mIndexMap.keyAt(i); if (device != AudioSystem.DEVICE_OUT_DEFAULT) { if (mIsMuted) { if (isFullyMuted()) { index = 0; } else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device) && isAvrcpAbsVolSupported) { Loading @@ -5685,7 +5691,7 @@ public class AudioService extends IAudioService.Stub } // apply default volume last: by convention , default device volume will be used // by audio policy manager if no explicit volume is present for a given device type if (mIsMuted) { if (isFullyMuted()) { index = 0; } else { index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10; Loading Loading @@ -5867,6 +5873,41 @@ public class AudioService extends IAudioService.Stub return changed; } /** * Mute/unmute the stream by AudioService * @param state the new mute state * @return true if the mute state was changed */ public boolean muteInternally(boolean state) { boolean changed = false; synchronized (VolumeStreamState.class) { if (state != mIsMutedInternally) { changed = true; mIsMutedInternally = state; // Set the new mute volume. This propagates the values to // the audio system, otherwise the volume won't be changed // at the lower level. sendMsg(mAudioHandler, MSG_SET_ALL_VOLUMES, SENDMSG_QUEUE, 0, 0, this, 0); } } if (changed) { sVolumeLogger.log(new VolumeEvent( VolumeEvent.VOL_MUTE_STREAM_INT, mStreamType, state)); } return changed; } @GuardedBy("VolumeStreamState.class") public boolean isFullyMuted() { return mIsMuted || mIsMutedInternally; } public int getStreamType() { return mStreamType; } Loading Loading @@ -5903,6 +5944,8 @@ public class AudioService extends IAudioService.Stub private void dump(PrintWriter pw) { pw.print(" Muted: "); pw.println(mIsMuted); pw.print(" Muted Internally: "); pw.println(mIsMutedInternally); pw.print(" Min: "); pw.print((mIndexMin + 5) / 10); if (mIndexMin != mIndexMinNoPerm) { Loading
services/core/java/com/android/server/audio/AudioServiceEvents.java +21 −0 Original line number Diff line number Diff line Loading @@ -100,6 +100,7 @@ public class AudioServiceEvents { static final int VOL_VOICE_ACTIVITY_HEARING_AID = 6; static final int VOL_MODE_CHANGE_HEARING_AID = 7; static final int VOL_SET_GROUP_VOL = 8; static final int VOL_MUTE_STREAM_INT = 9; final int mOp; final int mStream; Loading Loading @@ -188,6 +189,18 @@ public class AudioServiceEvents { logMetricEvent(); } /** used for VOL_MUTE_STREAM_INT */ VolumeEvent(int op, int stream, boolean state) { mOp = op; mStream = stream; mVal1 = state ? 1 : 0; mVal2 = 0; mCaller = null; mGroupName = null; mAudioAttributes = null; logMetricEvent(); } /** * Audio Analytics unique Id. Loading Loading @@ -278,6 +291,9 @@ public class AudioServiceEvents { .set(MediaMetrics.Property.INDEX, mVal1) .record(); return; case VOL_MUTE_STREAM_INT: // No value in logging metrics for this internal event return; default: return; } Loading Loading @@ -343,6 +359,11 @@ public class AudioServiceEvents { .append(" flags:0x").append(Integer.toHexString(mVal2)) .append(") from ").append(mCaller) .toString(); case VOL_MUTE_STREAM_INT: return new StringBuilder("VolumeStreamState.muteInternally(stream:") .append(AudioSystem.streamToString(mStream)) .append(mVal1 == 1 ? ", muted)" : ", unmuted)") .toString(); default: return new StringBuilder("FIXME invalid op:").append(mOp).toString(); } } Loading