diff options
6 files changed, 148 insertions, 135 deletions
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 33ad49edfe87..e3cd9932c4c1 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -127,8 +127,7 @@ public class AudioDeviceBroker { private final Object mDeviceStateLock = new Object(); // Request to override default use of A2DP for media. - @GuardedBy("mDeviceStateLock") - private boolean mBluetoothA2dpEnabled; + private AtomicBoolean mBluetoothA2dpEnabled = new AtomicBoolean(false); // lock always taken when accessing AudioService.mSetModeDeathHandlers // TODO do not "share" the lock between AudioService and BtHelpr, see b/123769055 @@ -263,7 +262,7 @@ public class AudioDeviceBroker { * Handle BluetoothHeadset intents where the action is one of * {@link BluetoothHeadset#ACTION_ACTIVE_DEVICE_CHANGED} or * {@link BluetoothHeadset#ACTION_AUDIO_STATE_CHANGED}. - * @param intent + * @param intent the Intent received from BT service */ private void onReceiveBtEvent(@NonNull Intent intent) { mBtHelper.onReceiveBtEvent(intent); @@ -275,22 +274,16 @@ public class AudioDeviceBroker { } /*package*/ void setBluetoothA2dpOn_Async(boolean on, String source) { - synchronized (mDeviceStateLock) { - if (mBluetoothA2dpEnabled == on) { - return; - } - mBluetoothA2dpEnabled = on; - mBrokerHandler.removeMessages(MSG_IIL_SET_FORCE_BT_A2DP_USE); - sendIILMsgNoDelay(MSG_IIL_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE, - AudioSystem.FOR_MEDIA, - mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP, - source); - } + boolean wasOn = mBluetoothA2dpEnabled.getAndSet(on); + // do not mute music if we do not anticipate a change in A2DP ON state + sendLMsgNoDelay(wasOn == on + ? MSG_L_SET_FORCE_BT_A2DP_USE_NO_MUTE : MSG_L_SET_FORCE_BT_A2DP_USE, + SENDMSG_REPLACE, source); } /** * Turns speakerphone on/off - * @param on + * @param on true to enable speakerphone * @param eventSource for logging purposes */ /*package*/ void setSpeakerphoneOn( @@ -304,21 +297,21 @@ public class AudioDeviceBroker { on, BtHelper.SCO_MODE_UNDEFINED, eventSource, isPrivileged)); } + private static final long SET_COMMUNICATION_DEVICE_TIMEOUT_MS = 3000; + + /** synchronization for setCommunicationDevice() and getCommunicationDevice */ + private final Object mCommunicationDeviceLock = new Object(); + @GuardedBy("mCommunicationDeviceLock") + private int mCommunicationDeviceUpdateCount = 0; + /** * Select device for use for communication use cases. * @param cb Client binder for death detection * @param uid Client uid * @param device Device selected or null to unselect. * @param eventSource for logging purposes + * @return false if there is no device and no communication client */ - - private static final long SET_COMMUNICATION_DEVICE_TIMEOUT_MS = 3000; - - /** synchronization for setCommunicationDevice() and getCommunicationDevice */ - private Object mCommunicationDeviceLock = new Object(); - @GuardedBy("mCommunicationDeviceLock") - private int mCommunicationDeviceUpdateCount = 0; - /*package*/ boolean setCommunicationDevice(IBinder cb, int uid, AudioDeviceInfo device, boolean isPrivileged, String eventSource) { @@ -349,7 +342,6 @@ public class AudioDeviceBroker { * Sets or resets the communication device for matching client. If no client matches and the * request is to reset for a given device (deviceInfo.mOn == false), the method is a noop. * @param deviceInfo information on the device and requester {@link #CommunicationDeviceInfo} - * @return true if the communication device is set or reset */ @GuardedBy("mDeviceStateLock") /*package*/ void onSetCommunicationDeviceForClient(CommunicationDeviceInfo deviceInfo) { @@ -736,15 +728,6 @@ public class AudioDeviceBroker { } /** - * Helper method on top of isDeviceRequestedForCommunication() indicating if - * speakerphone ON is currently requested or not. - * @return true if speakerphone ON requested, false otherwise. - */ - private boolean isSpeakerphoneRequested() { - return isDeviceRequestedForCommunication(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER); - } - - /** * Indicates if preferred route selection for communication is speakerphone. * @return true if speakerphone is active, false otherwise. */ @@ -931,6 +914,12 @@ public class AudioDeviceBroker { } @Override + public int hashCode() { + // only hashing on the fields used in equals() + return Objects.hash(mProfile, mDevice); + } + + @Override public String toString() { return "BtDeviceInfo: device=" + mDevice.toString() + " state=" + mState @@ -987,7 +976,7 @@ public class AudioDeviceBroker { /** * will block on mDeviceStateLock, which is held during an A2DP (dis) connection * not just a simple message post - * @param info struct with the (dis)connection information + * @param data struct with the (dis)connection information */ /*package*/ void queueOnBluetoothActiveDeviceChanged(@NonNull BtDeviceChangedData data) { if (data.mPreviousDevice != null @@ -1231,16 +1220,8 @@ public class AudioDeviceBroker { } } - /*package*/ boolean isAvrcpAbsoluteVolumeSupported() { - synchronized (mDeviceStateLock) { - return mBtHelper.isAvrcpAbsoluteVolumeSupported(); - } - } - /*package*/ boolean isBluetoothA2dpOn() { - synchronized (mDeviceStateLock) { - return mBluetoothA2dpEnabled; - } + return mBluetoothA2dpEnabled.get(); } /*package*/ void postSetAvrcpAbsoluteVolumeIndex(int index) { @@ -1384,6 +1365,7 @@ public class AudioDeviceBroker { mCommDevDispatchers.getBroadcastItem(i) .dispatchCommunicationDeviceChanged(portId); } catch (RemoteException e) { + Log.e(TAG, "dispatchCommunicationDevice error", e); } } mCommDevDispatchers.finishBroadcast(); @@ -1543,8 +1525,9 @@ public class AudioDeviceBroker { sendLMsgNoDelay(MSG_L_SYNCHRONIZE_ADI_DEVICES_IN_INVENTORY, SENDMSG_QUEUE, deviceState); } - /*package*/ void postUpdatedAdiDeviceState(AdiDeviceState deviceState) { - sendLMsgNoDelay(MSG_L_UPDATED_ADI_DEVICE_STATE, SENDMSG_QUEUE, deviceState); + /*package*/ void postUpdatedAdiDeviceState(AdiDeviceState deviceState, boolean initSA) { + sendILMsgNoDelay( + MSG_IL_UPDATED_ADI_DEVICE_STATE, SENDMSG_QUEUE, initSA ? 1 : 0, deviceState); } /*package*/ static final class CommunicationDeviceInfo { @@ -1586,6 +1569,12 @@ public class AudioDeviceBroker { } @Override + public int hashCode() { + // only hashing on the fields used in equals() + return Objects.hash(mCb.hashCode(), mUid); + } + + @Override public String toString() { return "CommunicationDeviceInfo mCb=" + mCb.toString() + " mUid=" + mUid @@ -1605,19 +1594,16 @@ public class AudioDeviceBroker { //@GuardedBy("mConnectedDevices") /*package*/ void setBluetoothA2dpOnInt(boolean on, boolean fromA2dp, String source) { // for logging only - final String eventSource = new StringBuilder("setBluetoothA2dpOn(").append(on) - .append(") from u/pid:").append(Binder.getCallingUid()).append("/") - .append(Binder.getCallingPid()).append(" src:").append(source).toString(); + final String eventSource = "setBluetoothA2dpOn(" + on + + ") from u/pid:" + Binder.getCallingUid() + "/" + + Binder.getCallingPid() + " src:" + source; - synchronized (mDeviceStateLock) { - mBluetoothA2dpEnabled = on; - mBrokerHandler.removeMessages(MSG_IIL_SET_FORCE_BT_A2DP_USE); - onSetForceUse( - AudioSystem.FOR_MEDIA, - mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP, - fromA2dp, - eventSource); - } + mBluetoothA2dpEnabled.set(on); + onSetForceUse( + AudioSystem.FOR_MEDIA, + on ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP, + fromA2dp, + eventSource); } /*package*/ boolean handleDeviceConnection(@NonNull AudioDeviceAttributes attributes, @@ -1654,6 +1640,10 @@ public class AudioDeviceBroker { sendIILMsg(MSG_IIL_BTLEAUDIO_TIMEOUT, SENDMSG_QUEUE, device, codec, address, delayMs); } + /*package*/ void setHearingAidTimeout(String address, int delayMs) { + sendLMsg(MSG_IL_BT_HEARING_AID_TIMEOUT, SENDMSG_QUEUE, address, delayMs); + } + /*package*/ void setAvrcpAbsoluteVolumeSupported(boolean supported) { synchronized (mDeviceStateLock) { mBtHelper.setAvrcpAbsoluteVolumeSupported(supported); @@ -1666,9 +1656,7 @@ public class AudioDeviceBroker { } /*package*/ boolean getBluetoothA2dpEnabled() { - synchronized (mDeviceStateLock) { - return mBluetoothA2dpEnabled; - } + return mBluetoothA2dpEnabled.get(); } /*package*/ int getLeAudioDeviceGroupId(BluetoothDevice device) { @@ -1829,9 +1817,13 @@ public class AudioDeviceBroker { } break; case MSG_IIL_SET_FORCE_USE: // intended fall-through - case MSG_IIL_SET_FORCE_BT_A2DP_USE: - onSetForceUse(msg.arg1, msg.arg2, - (msg.what == MSG_IIL_SET_FORCE_BT_A2DP_USE), (String) msg.obj); + onSetForceUse(msg.arg1, msg.arg2, false, (String) msg.obj); + break; + case MSG_L_SET_FORCE_BT_A2DP_USE: + case MSG_L_SET_FORCE_BT_A2DP_USE_NO_MUTE: + int forcedUsage = mBluetoothA2dpEnabled.get() + ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP; + onSetForceUse(AudioSystem.FOR_MEDIA, forcedUsage, true, (String) msg.obj); break; case MSG_REPORT_NEW_ROUTES: case MSG_REPORT_NEW_ROUTES_A2DP: @@ -1839,35 +1831,38 @@ public class AudioDeviceBroker { mDeviceInventory.onReportNewRoutes(); } break; - case MSG_L_SET_BT_ACTIVE_DEVICE: - synchronized (mSetModeLock) { - synchronized (mDeviceStateLock) { - final BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj; - if (btInfo.mState == BluetoothProfile.STATE_CONNECTED - && !mBtHelper.isProfilePoxyConnected(btInfo.mProfile)) { - AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( - "msg: MSG_L_SET_BT_ACTIVE_DEVICE " - + "received with null profile proxy: " - + btInfo)).printLog(TAG)); - } else { - @AudioSystem.AudioFormatNativeEnumForBtCodec final int codec = - mBtHelper.getCodecWithFallback(btInfo.mDevice, - btInfo.mProfile, btInfo.mIsLeOutput, - "MSG_L_SET_BT_ACTIVE_DEVICE"); + case MSG_L_SET_BT_ACTIVE_DEVICE: { + final BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj; + if (btInfo.mState == BluetoothProfile.STATE_CONNECTED + && !mBtHelper.isProfilePoxyConnected(btInfo.mProfile)) { + AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( + "msg: MSG_L_SET_BT_ACTIVE_DEVICE " + + "received with null profile proxy: " + + btInfo)).printLog(TAG)); + } else { + @AudioSystem.AudioFormatNativeEnumForBtCodec final int codec = + mBtHelper.getCodecWithFallback(btInfo.mDevice, + btInfo.mProfile, btInfo.mIsLeOutput, + "MSG_L_SET_BT_ACTIVE_DEVICE"); + synchronized (mSetModeLock) { + synchronized (mDeviceStateLock) { mDeviceInventory.onSetBtActiveDevice(btInfo, codec, (btInfo.mProfile - != BluetoothProfile.LE_AUDIO || btInfo.mIsLeOutput) + != BluetoothProfile.LE_AUDIO + || btInfo.mIsLeOutput) ? mAudioService.getBluetoothContextualVolumeStream() : AudioSystem.STREAM_DEFAULT); if (btInfo.mProfile == BluetoothProfile.LE_AUDIO - || btInfo.mProfile == BluetoothProfile.HEARING_AID) { - onUpdateCommunicationRouteClient(isBluetoothScoRequested(), + || btInfo.mProfile + == BluetoothProfile.HEARING_AID) { + onUpdateCommunicationRouteClient( + isBluetoothScoRequested(), "setBluetoothActiveDevice"); } } } } - break; + } break; case MSG_BT_HEADSET_CNCT_FAILED: synchronized (mSetModeLock) { synchronized (mDeviceStateLock) { @@ -1889,13 +1884,20 @@ public class AudioDeviceBroker { (String) msg.obj, msg.arg1, msg.arg2); } break; + case MSG_IL_BT_HEARING_AID_TIMEOUT: + // msg.obj == address of Hearing Aid device + synchronized (mDeviceStateLock) { + mDeviceInventory.onMakeHearingAidDeviceUnavailableNow( + (String) msg.obj); + } + break; case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE: { final BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj; + @AudioSystem.AudioFormatNativeEnumForBtCodec final int codec = + mBtHelper.getCodecWithFallback(btInfo.mDevice, + btInfo.mProfile, btInfo.mIsLeOutput, + "MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE"); synchronized (mDeviceStateLock) { - @AudioSystem.AudioFormatNativeEnumForBtCodec final int codec = - mBtHelper.getCodecWithFallback(btInfo.mDevice, - btInfo.mProfile, btInfo.mIsLeOutput, - "MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE"); mDeviceInventory.onBluetoothDeviceConfigChange( btInfo, codec, BtHelper.EVENT_DEVICE_CONFIG_CHANGE); } @@ -2074,8 +2076,8 @@ public class AudioDeviceBroker { } } break; - case MSG_L_UPDATED_ADI_DEVICE_STATE: - mAudioService.onUpdatedAdiDeviceState((AdiDeviceState) msg.obj); + case MSG_IL_UPDATED_ADI_DEVICE_STATE: + mAudioService.onUpdatedAdiDeviceState((AdiDeviceState) msg.obj, msg.arg1 == 1); break; default: @@ -2106,7 +2108,7 @@ public class AudioDeviceBroker { private static final int MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE = 2; private static final int MSG_I_BROADCAST_BT_CONNECTION_STATE = 3; private static final int MSG_IIL_SET_FORCE_USE = 4; - private static final int MSG_IIL_SET_FORCE_BT_A2DP_USE = 5; + private static final int MSG_L_SET_FORCE_BT_A2DP_USE = 5; private static final int MSG_TOGGLE_HDMI = 6; private static final int MSG_L_SET_BT_ACTIVE_DEVICE = 7; private static final int MSG_BT_HEADSET_CNCT_FAILED = 9; @@ -2162,9 +2164,9 @@ public class AudioDeviceBroker { private static final int MSG_CHECK_COMMUNICATION_ROUTE_CLIENT_STATE = 56; private static final int MSG_I_UPDATE_LE_AUDIO_GROUP_ADDRESSES = 57; private static final int MSG_L_SYNCHRONIZE_ADI_DEVICES_IN_INVENTORY = 58; - private static final int MSG_L_UPDATED_ADI_DEVICE_STATE = 59; - - + private static final int MSG_IL_UPDATED_ADI_DEVICE_STATE = 59; + private static final int MSG_L_SET_FORCE_BT_A2DP_USE_NO_MUTE = 60; + private static final int MSG_IL_BT_HEARING_AID_TIMEOUT = 61; private static boolean isMessageHandledUnderWakelock(int msgId) { switch(msgId) { @@ -2177,6 +2179,7 @@ public class AudioDeviceBroker { case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT: case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT: case MSG_CHECK_MUTE_MUSIC: + case MSG_IL_BT_HEARING_AID_TIMEOUT: return true; default: return false; @@ -2205,10 +2208,6 @@ public class AudioDeviceBroker { sendIILMsg(msg, existingMsgPolicy, 0, 0, obj, delay); } - private void sendIMsg(int msg, int existingMsgPolicy, int arg, int delay) { - sendIILMsg(msg, existingMsgPolicy, arg, 0, null, delay); - } - private void sendMsgNoDelay(int msg, int existingMsgPolicy) { sendIILMsg(msg, existingMsgPolicy, 0, 0, null, 0); } @@ -2265,6 +2264,7 @@ public class AudioDeviceBroker { case MSG_IL_BTA2DP_TIMEOUT: case MSG_IIL_BTLEAUDIO_TIMEOUT: case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE: + case MSG_IL_BT_HEARING_AID_TIMEOUT: if (sLastDeviceConnectMsgTime >= time) { // add a little delay to make sure messages are ordered as expected time = sLastDeviceConnectMsgTime + 30; @@ -2303,7 +2303,7 @@ public class AudioDeviceBroker { MESSAGES_MUTE_MUSIC.add(MSG_L_SET_BT_ACTIVE_DEVICE); MESSAGES_MUTE_MUSIC.add(MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE); MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT); - MESSAGES_MUTE_MUSIC.add(MSG_IIL_SET_FORCE_BT_A2DP_USE); + MESSAGES_MUTE_MUSIC.add(MSG_L_SET_FORCE_BT_A2DP_USE); } private AtomicBoolean mMusicMuted = new AtomicBoolean(false); diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index da13ad0641cf..1f0f8c466cd5 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -169,7 +169,7 @@ public class AudioDeviceInventory { if (ads != null) { if (ads.getAudioDeviceCategory() != category) { ads.setAudioDeviceCategory(category); - mDeviceBroker.postUpdatedAdiDeviceState(ads); + mDeviceBroker.postUpdatedAdiDeviceState(ads, false /*initSA*/); mDeviceBroker.postPersistAudioDeviceSettings(); } mDeviceBroker.postSynchronizeAdiDevicesInInventory(ads); @@ -182,7 +182,7 @@ public class AudioDeviceInventory { mDeviceInventory.put(ads.getDeviceId(), ads); checkDeviceInventorySize_l(); - mDeviceBroker.postUpdatedAdiDeviceState(ads); + mDeviceBroker.postUpdatedAdiDeviceState(ads, true /*initSA*/); mDeviceBroker.postPersistAudioDeviceSettings(); } } @@ -212,7 +212,7 @@ public class AudioDeviceInventory { checkDeviceInventorySize_l(); } if (updatedCategory.get()) { - mDeviceBroker.postUpdatedAdiDeviceState(deviceState); + mDeviceBroker.postUpdatedAdiDeviceState(deviceState, false /*initSA*/); } mDeviceBroker.postSynchronizeAdiDevicesInInventory(deviceState); } @@ -314,7 +314,7 @@ public class AudioDeviceInventory { } ads2.setAudioDeviceCategory(updatedDevice.getAudioDeviceCategory()); - mDeviceBroker.postUpdatedAdiDeviceState(ads2); + mDeviceBroker.postUpdatedAdiDeviceState(ads2, false /*initSA*/); AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( "synchronizeBleDeviceInInventory synced device pair ads1=" + updatedDevice + " ads2=" + ads2).printLog(TAG)); @@ -335,7 +335,7 @@ public class AudioDeviceInventory { } ads2.setAudioDeviceCategory(updatedDevice.getAudioDeviceCategory()); - mDeviceBroker.postUpdatedAdiDeviceState(ads2); + mDeviceBroker.postUpdatedAdiDeviceState(ads2, false /*initSA*/); AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( "synchronizeBleDeviceInInventory synced device pair ads1=" + updatedDevice + " peer ads2=" + ads2).printLog(TAG)); @@ -360,7 +360,7 @@ public class AudioDeviceInventory { } ads.setAudioDeviceCategory(updatedDevice.getAudioDeviceCategory()); - mDeviceBroker.postUpdatedAdiDeviceState(ads); + mDeviceBroker.postUpdatedAdiDeviceState(ads, false /*initSA*/); AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( "synchronizeDeviceProfilesInInventory synced device pair ads1=" + updatedDevice + " ads2=" + ads).printLog(TAG)); @@ -444,7 +444,7 @@ public class AudioDeviceInventory { @Override public DeviceInfo put(String key, DeviceInfo value) { final DeviceInfo result = super.put(key, value); - record("put", true /* connected */, key, value); + record("put", true /* connected */, value); return result; } @@ -452,7 +452,7 @@ public class AudioDeviceInventory { public DeviceInfo putIfAbsent(String key, DeviceInfo value) { final DeviceInfo result = super.putIfAbsent(key, value); if (result == null) { - record("putIfAbsent", true /* connected */, key, value); + record("putIfAbsent", true /* connected */, value); } return result; } @@ -461,7 +461,7 @@ public class AudioDeviceInventory { public DeviceInfo remove(Object key) { final DeviceInfo result = super.remove(key); if (result != null) { - record("remove", false /* connected */, (String) key, result); + record("remove", false /* connected */, result); } return result; } @@ -470,7 +470,7 @@ public class AudioDeviceInventory { public boolean remove(Object key, Object value) { final boolean result = super.remove(key, value); if (result) { - record("remove", false /* connected */, (String) key, (DeviceInfo) value); + record("remove", false /* connected */, (DeviceInfo) value); } return result; } @@ -484,7 +484,7 @@ public class AudioDeviceInventory { // putAll // replace // replaceAll - private void record(String event, boolean connected, String key, DeviceInfo value) { + private void record(String event, boolean connected, DeviceInfo value) { // DeviceInfo - int mDeviceType; // DeviceInfo - int mDeviceCodecFormat; new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE @@ -657,7 +657,7 @@ public class AudioDeviceInventory { /** * A class just for packaging up a set of connection parameters. */ - /*package*/ class WiredDeviceConnectionState { + /*package*/ static class WiredDeviceConnectionState { public final AudioDeviceAttributes mAttributes; public final @AudioService.ConnectionState int mState; public final String mCaller; @@ -961,6 +961,11 @@ public class AudioDeviceInventory { } } + /*package*/ void onMakeHearingAidDeviceUnavailableNow(String address) { + synchronized (mDevicesLock) { + makeHearingAidDeviceUnavailable(address); + } + } /** * Goes over all connected LE Audio devices in the provided group ID and @@ -1021,7 +1026,9 @@ public class AudioDeviceInventory { IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(n); try { obs.dispatchAudioRoutesChanged(routes); - } catch (RemoteException e) { } + } catch (RemoteException e) { + Log.e(TAG, "onReportNewRoutes", e); + } } } mRoutesObservers.finishBroadcast(); @@ -1805,8 +1812,7 @@ public class AudioDeviceInventory { final int delay = checkSendBecomingNoisyIntentInt(DEVICE_OUT_HEARING_AID, AudioService.CONNECTION_STATE_DISCONNECTED, AudioSystem.DEVICE_NONE); toRemove.stream().forEach(deviceAddress -> - // TODO delay not used? - makeHearingAidDeviceUnavailable(deviceAddress /*, delay*/) + makeHearingAidDeviceUnavailableLater(deviceAddress, delay) ); } } @@ -2385,6 +2391,15 @@ public class AudioDeviceInventory { mDeviceBroker.postCheckCommunicationDeviceRemoval(ada); } + @GuardedBy("mDevicesLock") + private void makeHearingAidDeviceUnavailableLater( + String address, int delayMs) { + // the device will be made unavailable later, so consider it disconnected right away + mConnectedDevices.remove(DeviceInfo.makeDeviceListKey(DEVICE_OUT_HEARING_AID, address)); + // send the delayed message to make the device unavailable later + mDeviceBroker.setHearingAidTimeout(address, delayMs); + } + /** * Returns whether a device of type DEVICE_OUT_HEARING_AID is connected. * Visibility by APM plays no role @@ -2664,10 +2679,6 @@ public class AudioDeviceInventory { private static final String CONNECT_INTENT_KEY_PORT_NAME = "portName"; private static final String CONNECT_INTENT_KEY_STATE = "state"; private static final String CONNECT_INTENT_KEY_ADDRESS = "address"; - private static final String CONNECT_INTENT_KEY_HAS_PLAYBACK = "hasPlayback"; - private static final String CONNECT_INTENT_KEY_HAS_CAPTURE = "hasCapture"; - private static final String CONNECT_INTENT_KEY_HAS_MIDI = "hasMIDI"; - private static final String CONNECT_INTENT_KEY_DEVICE_CLASS = "class"; private void sendDeviceConnectionIntent(int device, int state, String address, String deviceName) { @@ -2830,6 +2841,7 @@ public class AudioDeviceInventory { mPrefDevDispatchers.getBroadcastItem(i).dispatchPrefDevicesChanged( strategy, devices); } catch (RemoteException e) { + Log.e(TAG, "dispatchPreferredDevice ", e); } } mPrefDevDispatchers.finishBroadcast(); @@ -2846,6 +2858,7 @@ public class AudioDeviceInventory { mNonDefDevDispatchers.getBroadcastItem(i).dispatchNonDefDevicesChanged( strategy, devices); } catch (RemoteException e) { + Log.e(TAG, "dispatchNonDefaultDevice ", e); } } mNonDefDevDispatchers.finishBroadcast(); @@ -2862,6 +2875,7 @@ public class AudioDeviceInventory { mDevRoleCapturePresetDispatchers.getBroadcastItem(i).dispatchDevicesRoleChanged( capturePreset, role, devices); } catch (RemoteException e) { + Log.e(TAG, "dispatchDevicesRoleForCapturePreset ", e); } } mDevRoleCapturePresetDispatchers.finishBroadcast(); @@ -2927,7 +2941,7 @@ public class AudioDeviceInventory { /** * Check if device is in the list of connected devices - * @param device + * @param device the device to query * @return true if connected */ @VisibleForTesting diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 6787fa6a68c6..8543a16202bf 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -11265,7 +11265,8 @@ public class AudioService extends IAudioService.Stub mDeviceBroker.addOrUpdateBtAudioDeviceCategoryInInventory(deviceState); mDeviceBroker.postPersistAudioDeviceSettings(); - mSpatializerHelper.refreshDevice(deviceState.getAudioDeviceAttributes()); + mSpatializerHelper.refreshDevice(deviceState.getAudioDeviceAttributes(), + false /* initState */); mSoundDoseHelper.setAudioDeviceCategory(addr, internalType, btAudioDeviceCategory == AUDIO_DEVICE_CATEGORY_HEADPHONES); } @@ -11336,11 +11337,11 @@ public class AudioService extends IAudioService.Stub /** Update the sound dose and spatializer state based on the new AdiDeviceState. */ @VisibleForTesting(visibility = PACKAGE) - public void onUpdatedAdiDeviceState(AdiDeviceState deviceState) { + public void onUpdatedAdiDeviceState(AdiDeviceState deviceState, boolean initSA) { if (deviceState == null) { return; } - mSpatializerHelper.refreshDevice(deviceState.getAudioDeviceAttributes()); + mSpatializerHelper.refreshDevice(deviceState.getAudioDeviceAttributes(), initSA); mSoundDoseHelper.setAudioDeviceCategory(deviceState.getDeviceAddress(), deviceState.getInternalDeviceType(), deviceState.getAudioDeviceCategory() == AUDIO_DEVICE_CATEGORY_HEADPHONES); diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index 73ca6fbf8e5f..8dc8af547c0e 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -235,10 +235,6 @@ public class BtHelper { mDeviceBroker.setForceUse_Async(AudioSystem.FOR_MEDIA, forMed, "onAudioServerDied()"); } - /*package*/ synchronized boolean isAvrcpAbsoluteVolumeSupported() { - return (mA2dp != null && mAvrcpAbsVolSupported); - } - /*package*/ synchronized void setAvrcpAbsoluteVolumeSupported(boolean supported) { mAvrcpAbsVolSupported = supported; Log.i(TAG, "setAvrcpAbsoluteVolumeSupported supported=" + supported); @@ -653,8 +649,6 @@ public class BtHelper { } } - // @GuardedBy("mDeviceBroker.mSetModeLock") - @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock") /*package*/ synchronized boolean isProfilePoxyConnected(int profile) { switch (profile) { case BluetoothProfile.HEADSET: diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java index 4426f8d9893a..831679bca79f 100644 --- a/services/core/java/com/android/server/audio/SpatializerHelper.java +++ b/services/core/java/com/android/server/audio/SpatializerHelper.java @@ -295,11 +295,11 @@ public class SpatializerHelper { // could have been called another time after boot in case of audioserver restart addCompatibleAudioDevice( new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, ""), - false /*forceEnable*/); + false /*forceEnable*/, false /*forceInit*/); // not force-enabling as this device might already be in the device list addCompatibleAudioDevice( new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, ""), - false /*forceEnable*/); + false /*forceEnable*/, false /*forceInit*/); } catch (RemoteException e) { resetCapabilities(); } finally { @@ -523,7 +523,7 @@ public class SpatializerHelper { } synchronized void addCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) { - addCompatibleAudioDevice(ada, true /*forceEnable*/); + addCompatibleAudioDevice(ada, true /*forceEnable*/, false /*forceInit*/); } /** @@ -537,7 +537,7 @@ public class SpatializerHelper { */ @GuardedBy("this") private void addCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada, - boolean forceEnable) { + boolean forceEnable, boolean forceInit) { if (!isDeviceCompatibleWithSpatializationModes(ada)) { return; } @@ -545,6 +545,9 @@ public class SpatializerHelper { final AdiDeviceState deviceState = findSACompatibleDeviceStateForAudioDeviceAttributes(ada); AdiDeviceState updatedDevice = null; // non-null on update. if (deviceState != null) { + if (forceInit) { + initSAState(deviceState); + } if (forceEnable && !deviceState.isSAEnabled()) { updatedDevice = deviceState; updatedDevice.setSAEnabled(true); @@ -753,10 +756,10 @@ public class SpatializerHelper { } } - synchronized void refreshDevice(@NonNull AudioDeviceAttributes ada) { + synchronized void refreshDevice(@NonNull AudioDeviceAttributes ada, boolean initState) { final AdiDeviceState deviceState = findSACompatibleDeviceStateForAudioDeviceAttributes(ada); if (isAvailableForAdiDeviceState(deviceState)) { - addCompatibleAudioDevice(ada, /*forceEnable=*/deviceState.isSAEnabled()); + addCompatibleAudioDevice(ada, /*forceEnable=*/deviceState.isSAEnabled(), initState); setHeadTrackerEnabled(deviceState.isHeadTrackerEnabled(), ada); } else { removeCompatibleAudioDevice(ada); diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java index f1c1dc365b90..59f4d56b44f1 100644 --- a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java +++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java @@ -24,6 +24,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; @@ -315,7 +316,7 @@ public class AudioDeviceBrokerTest { mFakeBtDevice.getAddress())); verify(mMockAudioService, timeout(MAX_MESSAGE_HANDLING_DELAY_MS).times(0)).onUpdatedAdiDeviceState( - eq(devState)); + eq(devState), anyBoolean()); } // metadata set @@ -326,7 +327,7 @@ public class AudioDeviceBrokerTest { mFakeBtDevice.getAddress())); verify(mMockAudioService, timeout(MAX_MESSAGE_HANDLING_DELAY_MS)).onUpdatedAdiDeviceState( - any()); + any(), anyBoolean()); } } finally { // reset the metadata device type @@ -354,7 +355,7 @@ public class AudioDeviceBrokerTest { verify(mMockAudioService, timeout(MAX_MESSAGE_HANDLING_DELAY_MS).atLeast(1)).onUpdatedAdiDeviceState( ArgumentMatchers.argThat(devState -> devState.getAudioDeviceCategory() - == AudioManager.AUDIO_DEVICE_CATEGORY_OTHER)); + == AudioManager.AUDIO_DEVICE_CATEGORY_OTHER), anyBoolean()); } private void doTestConnectionDisconnectionReconnection(int delayAfterDisconnection, |