From 5bbcd44ce50d0319f23337afd694dbb117685207 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Thu, 18 Apr 2019 12:07:34 -0700 Subject: AudioService: async volume updates from DeviceInventory Make VolumeStreamState private to AudioService, and don't let AudioDeviceBroker, AudioDeviceInventory manipulate it. Only let them post messages on AudioService message handler to access them. Refactor methods to set a volume index and observe devices from AudioDeviceInventory to AudioService to be asynchronous. Bug: 130686447 Bug: 129163231 Test: verify volume is last used when connecting A2DP or hearing aid Change-Id: I356af79213f4c21ed4ebaf86922fbbd9bf48a892 --- .../android/server/audio/AudioDeviceBroker.java | 22 +++-- .../android/server/audio/AudioDeviceInventory.java | 36 +++---- .../com/android/server/audio/AudioService.java | 108 ++++++++++++++++++++- .../java/com/android/server/audio/BtHelper.java | 3 +- 4 files changed, 130 insertions(+), 39 deletions(-) diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index c573332235d8..4ce6d91d25b0 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -43,7 +43,6 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; -import java.util.ArrayList; /** @hide */ /*package*/ final class AudioDeviceBroker { @@ -376,24 +375,29 @@ import java.util.ArrayList; mAudioService.postAccessoryPlugMediaUnmute(device); } - /*package*/ AudioService.VolumeStreamState getStreamState(int streamType) { - return mAudioService.getStreamState(streamType); + /*package*/ int getVssVolumeForDevice(int streamType, int device) { + return mAudioService.getVssVolumeForDevice(streamType, device); } - /*package*/ ArrayList getSetModeDeathHandlers() { - return mAudioService.mSetModeDeathHandlers; + /*package*/ int getModeOwnerPid() { + return mAudioService.getModeOwnerPid(); } /*package*/ int getDeviceForStream(int streamType) { return mAudioService.getDeviceForStream(streamType); } - /*package*/ void setDeviceVolume(AudioService.VolumeStreamState streamState, int device) { - mAudioService.setDeviceVolume(streamState, device); + /*package*/ void postApplyVolumeOnDevice(int streamType, int device, String caller) { + mAudioService.postApplyVolumeOnDevice(streamType, device, caller); } - /*packages*/ void observeDevicesForAllStreams() { - mAudioService.observeDevicesForAllStreams(); + /*package*/ void postSetVolumeIndexOnDevice(int streamType, int vssVolIndex, int device, + String caller) { + mAudioService.postSetVolumeIndexOnDevice(streamType, vssVolIndex, device, caller); + } + + /*packages*/ void postObserveDevicesForAllStreams() { + mAudioService.postObserveDevicesForAllStreams(); } /*package*/ boolean isInCommunication() { diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index 91b51b4989d8..f9dbdd5b13db 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -198,14 +198,10 @@ public final class AudioDeviceInventory { } } if (a2dpVolume != -1) { - AudioService.VolumeStreamState streamState = - mDeviceBroker.getStreamState(AudioSystem.STREAM_MUSIC); - // Convert index to internal representation in VolumeStreamState - a2dpVolume = a2dpVolume * 10; - streamState.setIndex(a2dpVolume, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, - "onSetA2dpSinkConnectionState"); - mDeviceBroker.setDeviceVolume( - streamState, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); + mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC, + // convert index to internal representation in VolumeStreamState + a2dpVolume * 10, + AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "onSetA2dpSinkConnectionState"); } makeA2dpDeviceAvailable(address, BtHelper.getName(btDevice), "onSetA2dpSinkConnectionState", a2dpCodec); @@ -302,14 +298,11 @@ public final class AudioDeviceInventory { if (event == BtHelper.EVENT_ACTIVE_DEVICE_CHANGE) { // Device is connected if (a2dpVolume != -1) { - final AudioService.VolumeStreamState streamState = - mDeviceBroker.getStreamState(AudioSystem.STREAM_MUSIC); - // Convert index to internal representation in VolumeStreamState - a2dpVolume = a2dpVolume * 10; - streamState.setIndex(a2dpVolume, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, + mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC, + // convert index to internal representation in VolumeStreamState + a2dpVolume * 10, + AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "onBluetoothA2dpActiveDeviceChange"); - mDeviceBroker.setDeviceVolume( - streamState, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); } } else if (event == BtHelper.EVENT_DEVICE_CONFIG_CHANGE) { if (di.mDeviceCodecFormat != a2dpCodec) { @@ -352,7 +345,7 @@ public final class AudioDeviceInventory { } } mRoutesObservers.finishBroadcast(); - mDeviceBroker.observeDevicesForAllStreams(); + mDeviceBroker.postObserveDevicesForAllStreams(); } private static final int DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG = @@ -655,8 +648,6 @@ public final class AudioDeviceInventory { int a2dpCodec) { // enable A2DP before notifying A2DP connection to avoid unnecessary processing in // audio policy manager - AudioService.VolumeStreamState streamState = - mDeviceBroker.getStreamState(AudioSystem.STREAM_MUSIC); mDeviceBroker.setBluetoothA2dpOnInt(true, eventSource); AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, AudioSystem.DEVICE_STATE_AVAILABLE, address, name, a2dpCodec); @@ -727,8 +718,8 @@ public final class AudioDeviceInventory { @GuardedBy("mConnectedDevices") private void makeHearingAidDeviceAvailable(String address, String name, String eventSource) { - final int hearingAidVolIndex = mDeviceBroker.getStreamState(AudioSystem.STREAM_MUSIC) - .getIndex(AudioSystem.DEVICE_OUT_HEARING_AID); + final int hearingAidVolIndex = mDeviceBroker.getVssVolumeForDevice(AudioSystem.STREAM_MUSIC, + AudioSystem.DEVICE_OUT_HEARING_AID); mDeviceBroker.postSetHearingAidVolumeIndex(hearingAidVolIndex, AudioSystem.STREAM_MUSIC); AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID, @@ -739,9 +730,8 @@ public final class AudioDeviceInventory { new DeviceInfo(AudioSystem.DEVICE_OUT_HEARING_AID, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT)); mDeviceBroker.postAccessoryPlugMediaUnmute(AudioSystem.DEVICE_OUT_HEARING_AID); - mDeviceBroker.setDeviceVolume( - mDeviceBroker.getStreamState(AudioSystem.STREAM_MUSIC), - AudioSystem.DEVICE_OUT_HEARING_AID); + mDeviceBroker.postApplyVolumeOnDevice(AudioSystem.STREAM_MUSIC, + AudioSystem.DEVICE_OUT_HEARING_AID, "makeHearingAidDeviceAvailable"); setCurrentAudioRouteNameIfPossible(name); } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index d30a9d2b158e..ccce685ae060 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -258,6 +258,8 @@ public class AudioService extends IAudioService.Stub private static final int MSG_DISPATCH_AUDIO_SERVER_STATE = 23; private static final int MSG_ENABLE_SURROUND_FORMATS = 24; private static final int MSG_UPDATE_RINGER_MODE = 25; + private static final int MSG_SET_DEVICE_STREAM_VOLUME = 26; + private static final int MSG_OBSERVE_DEVICES_FOR_ALL_STREAMS = 27; // start of messages handled under wakelock // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(), // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...) @@ -274,8 +276,8 @@ public class AudioService extends IAudioService.Stub /** @see VolumeStreamState */ private VolumeStreamState[] mStreamStates; - /*package*/ VolumeStreamState getStreamState(int stream) { - return mStreamStates[stream]; + /*package*/ int getVssVolumeForDevice(int stream, int device) { + return mStreamStates[stream].getIndex(device); } private SettingsObserver mSettingsObserver; @@ -2920,7 +2922,21 @@ public class AudioService extends IAudioService.Stub } - /*package*/ class SetModeDeathHandler implements IBinder.DeathRecipient { + /** + * Return the pid of the current audio mode owner + * @return 0 if nobody owns the mode + */ + /*package*/ int getModeOwnerPid() { + int modeOwnerPid = 0; + try { + modeOwnerPid = mSetModeDeathHandlers.get(0).getPid(); + } catch (Exception e) { + // nothing to do, modeOwnerPid is not modified + } + return modeOwnerPid; + } + + private class SetModeDeathHandler implements IBinder.DeathRecipient { private IBinder mCb; // To be notified of client's death private int mPid; private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client @@ -4080,8 +4096,14 @@ public class AudioService extends IAudioService.Stub } } + /*package*/ void postObserveDevicesForAllStreams() { + sendMsg(mAudioHandler, + MSG_OBSERVE_DEVICES_FOR_ALL_STREAMS, + SENDMSG_QUEUE, 0 /*arg1*/, 0 /*arg2*/, null /*obj*/, + 0 /*delay*/); + } - /*package*/ void observeDevicesForAllStreams() { + private void onObserveDevicesForAllStreams() { observeDevicesForStreams(-1); } @@ -4254,7 +4276,7 @@ public class AudioService extends IAudioService.Stub // 2 mSetModeLock // 3 mSettingsLock // 4 VolumeStreamState.class - public class VolumeStreamState { + private class VolumeStreamState { private final int mStreamType; private int mIndexMin; private int mIndexMax; @@ -4724,6 +4746,74 @@ public class AudioService extends IAudioService.Stub } } + private static final class DeviceVolumeUpdate { + final int mStreamType; + final int mDevice; + final @NonNull String mCaller; + private static final int NO_NEW_INDEX = -2049; + private final int mVssVolIndex; + + // Constructor with volume index, meant to cause this volume to be set and applied for the + // given stream type on the given device + DeviceVolumeUpdate(int streamType, int vssVolIndex, int device, @NonNull String caller) { + mStreamType = streamType; + mVssVolIndex = vssVolIndex; + mDevice = device; + mCaller = caller; + } + + // Constructor with no volume index, meant to cause re-apply of volume for the given + // stream type on the given device + DeviceVolumeUpdate(int streamType, int device, @NonNull String caller) { + mStreamType = streamType; + mVssVolIndex = NO_NEW_INDEX; + mDevice = device; + mCaller = caller; + } + + boolean hasVolumeIndex() { + return mVssVolIndex != NO_NEW_INDEX; + } + + int getVolumeIndex() throws IllegalStateException { + Preconditions.checkState(mVssVolIndex != NO_NEW_INDEX); + return mVssVolIndex; + } + } + + /*package*/ void postSetVolumeIndexOnDevice(int streamType, int vssVolIndex, int device, + String caller) { + sendMsg(mAudioHandler, + MSG_SET_DEVICE_STREAM_VOLUME, + SENDMSG_QUEUE, 0 /*arg1*/, 0 /*arg2*/, + new DeviceVolumeUpdate(streamType, vssVolIndex, device, caller), + 0 /*delay*/); + } + + /*package*/ void postApplyVolumeOnDevice(int streamType, int device, @NonNull String caller) { + sendMsg(mAudioHandler, + MSG_SET_DEVICE_STREAM_VOLUME, + SENDMSG_QUEUE, 0 /*arg1*/, 0 /*arg2*/, + new DeviceVolumeUpdate(streamType, device, caller), + 0 /*delay*/); + } + + private void onSetVolumeIndexOnDevice(@NonNull DeviceVolumeUpdate update) { + synchronized (VolumeStreamState.class) { + final VolumeStreamState streamState = mStreamStates[update.mStreamType]; + if (update.hasVolumeIndex()) { + final int index = update.getVolumeIndex(); + streamState.setIndex(index, update.mDevice, update.mCaller); + sVolumeLogger.log(new AudioEventLogger.StringEvent(update.mCaller + " dev:0x" + + Integer.toHexString(update.mDevice) + " volIdx:" + index)); + } else { + sVolumeLogger.log(new AudioEventLogger.StringEvent(update.mCaller + + " update vol on dev:0x" + Integer.toHexString(update.mDevice))); + } + setDeviceVolume(streamState, update.mDevice); + } + } + /*package*/ void setDeviceVolume(VolumeStreamState streamState, int device) { final boolean isAvrcpAbsVolSupported = mDeviceBroker.isAvrcpAbsoluteVolumeSupported(); @@ -5164,6 +5254,14 @@ public class AudioService extends IAudioService.Stub case MSG_UPDATE_RINGER_MODE: onUpdateRingerModeServiceInt(); break; + + case MSG_SET_DEVICE_STREAM_VOLUME: + onSetVolumeIndexOnDevice((DeviceVolumeUpdate) msg.obj); + break; + + case MSG_OBSERVE_DEVICES_FOR_ALL_STREAMS: + onObserveDevicesForAllStreams(); + break; } } } diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index 332ff362392a..068c3d8a1264 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -765,8 +765,7 @@ public class BtHelper { broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING); // Accept SCO audio activation only in NORMAL audio mode or if the mode is // currently controlled by the same client process. - int modeOwnerPid = mDeviceBroker.getSetModeDeathHandlers().isEmpty() - ? 0 : mDeviceBroker.getSetModeDeathHandlers().get(0).getPid(); + final int modeOwnerPid = mDeviceBroker.getModeOwnerPid(); if (modeOwnerPid != 0 && (modeOwnerPid != mCreatorPid)) { Log.w(TAG, "requestScoState: audio mode is not NORMAL and modeOwnerPid " + modeOwnerPid + " != creatorPid " + mCreatorPid); -- cgit v1.2.3-59-g8ed1b