Loading services/core/java/com/android/server/audio/AudioDeviceBroker.java +145 −86 Original line number Original line Diff line number Diff line Loading @@ -80,9 +80,12 @@ import java.util.concurrent.atomic.AtomicBoolean; private final @NonNull AudioService mAudioService; private final @NonNull AudioService mAudioService; private final @NonNull Context mContext; private final @NonNull Context mContext; /** Forced device usage for communications sent to AudioSystem */ /** ID for Communication strategy retrieved form audio policy manager */ private AudioDeviceAttributes mPreferredCommunicationDevice; private int mCommunicationStrategyId = -1; private int mCommunicationStrategyId = -1; /** Active communication device reported by audio policy manager */ private AudioDeviceInfo mActiveCommunicationDevice; /** Last preferred device set for communication strategy */ private AudioDeviceAttributes mPreferredCommunicationDevice; // Manages all connected devices, only ever accessed on the message loop // Manages all connected devices, only ever accessed on the message loop private final AudioDeviceInventory mDeviceInventory; private final AudioDeviceInventory mDeviceInventory; Loading Loading @@ -153,8 +156,9 @@ import java.util.concurrent.atomic.AtomicBoolean; private void init() { private void init() { setupMessaging(mContext); setupMessaging(mContext); mPreferredCommunicationDevice = null; initCommunicationStrategyId(); initCommunicationStrategyId(); mPreferredCommunicationDevice = null; updateActiveCommunicationDevice(); mSystemServer.registerUserStartedReceiver(mContext); mSystemServer.registerUserStartedReceiver(mContext); } } Loading Loading @@ -300,7 +304,6 @@ import java.util.concurrent.atomic.AtomicBoolean; + " from API: " + eventSource)).printLog(TAG)); + " from API: " + eventSource)).printLog(TAG)); final boolean wasBtScoRequested = isBluetoothScoRequested(); final boolean wasBtScoRequested = isBluetoothScoRequested(); final boolean wasSpeakerphoneRequested = isSpeakerphoneRequested(); CommunicationRouteClient client; CommunicationRouteClient client; Loading Loading @@ -341,16 +344,6 @@ import java.util.concurrent.atomic.AtomicBoolean; mBtHelper.stopBluetoothSco(eventSource); mBtHelper.stopBluetoothSco(eventSource); } } if (wasSpeakerphoneRequested != isSpeakerphoneRequested()) { try { mContext.sendBroadcastAsUser( new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED) .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL); } catch (Exception e) { Log.w(TAG, "failed to broadcast ACTION_SPEAKERPHONE_STATE_CHANGED: " + e); } } sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE, SENDMSG_QUEUE, eventSource); sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE, SENDMSG_QUEUE, eventSource); } } Loading Loading @@ -386,9 +379,19 @@ import java.util.concurrent.atomic.AtomicBoolean; * Returns the device currently requested for communication use case. * Returns the device currently requested for communication use case. * @return AudioDeviceInfo the requested device for communication. * @return AudioDeviceInfo the requested device for communication. */ */ AudioDeviceInfo getCommunicationDevice() { /* package */ AudioDeviceInfo getCommunicationDevice() { synchronized (mDeviceStateLock) { synchronized (mDeviceStateLock) { AudioDeviceAttributes device = requestedCommunicationDevice(); updateActiveCommunicationDevice(); return mActiveCommunicationDevice; } } /** * Updates currently active communication device (mActiveCommunicationDevice). */ @GuardedBy("mDeviceStateLock") void updateActiveCommunicationDevice() { AudioDeviceAttributes device = preferredCommunicationDevice(); if (device == null) { if (device == null) { AudioAttributes attr = AudioAttributes attr = AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType( AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType( Loading @@ -396,56 +399,99 @@ import java.util.concurrent.atomic.AtomicBoolean; List<AudioDeviceAttributes> devices = AudioSystem.getDevicesForAttributes(attr); List<AudioDeviceAttributes> devices = AudioSystem.getDevicesForAttributes(attr); if (devices.isEmpty()) { if (devices.isEmpty()) { if (mAudioService.isPlatformVoice()) { if (mAudioService.isPlatformVoice()) { Log.w(TAG, "getCommunicationDevice(): no device for phone strategy"); Log.w(TAG, "updateActiveCommunicationDevice(): no device for phone strategy"); } } return null; mActiveCommunicationDevice = null; return; } } device = devices.get(0); device = devices.get(0); } } return AudioManager.getDeviceInfoFromTypeAndAddress( mActiveCommunicationDevice = AudioManager.getDeviceInfoFromTypeAndAddress( device.getType(), device.getAddress()); device.getType(), device.getAddress()); } } /** * Indicates if the device which type is passed as argument is currently resquested to be used * for communication. * @param deviceType the device type the query applies to. * @return true if this device type is requested for communication. */ private boolean isDeviceRequestedForCommunication(int deviceType) { synchronized (mDeviceStateLock) { AudioDeviceAttributes device = requestedCommunicationDevice(); return device != null && device.getType() == deviceType; } } /** * Indicates if the device which type is passed as argument is currently either resquested * to be used for communication or selected for an other reason (e.g bluetooth SCO audio * is active for SCO device). * @param deviceType the device type the query applies to. * @return true if this device type is requested for communication. */ private boolean isDeviceOnForCommunication(int deviceType) { synchronized (mDeviceStateLock) { AudioDeviceAttributes device = preferredCommunicationDevice(); return device != null && device.getType() == deviceType; } } /** * Indicates if the device which type is passed as argument is active for communication. * Active means not only currently used by audio policy manager for communication strategy * but also explicitly requested for use by communication strategy. * @param deviceType the device type the query applies to. * @return true if this device type is requested for communication. */ private boolean isDeviceActiveForCommunication(int deviceType) { return mActiveCommunicationDevice != null && mActiveCommunicationDevice.getType() == deviceType && mPreferredCommunicationDevice != null && mPreferredCommunicationDevice.getType() == deviceType; } } /** /** * Helper method on top of requestedCommunicationDevice() indicating if * Helper method on top of isDeviceRequestedForCommunication() indicating if * speakerphone ON is currently requested or not. * speakerphone ON is currently requested or not. * @return true if speakerphone ON requested, false otherwise. * @return true if speakerphone ON requested, false otherwise. */ */ private boolean isSpeakerphoneRequested() { private boolean isSpeakerphoneRequested() { synchronized (mDeviceStateLock) { return isDeviceRequestedForCommunication(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER); AudioDeviceAttributes device = requestedCommunicationDevice(); return device != null && device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER; } } } /** /** * Indicates if active route selection for communication is speakerphone. * Indicates if preferred route selection for communication is speakerphone. * @return true if speakerphone is active, false otherwise. * @return true if speakerphone is active, false otherwise. */ */ /*package*/ boolean isSpeakerphoneOn() { /*package*/ boolean isSpeakerphoneOn() { AudioDeviceAttributes device = getPreferredCommunicationDevice(); return isDeviceOnForCommunication(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER); if (device == null) { return false; } } return device.getInternalType() == AudioSystem.DEVICE_OUT_SPEAKER; private boolean isSpeakerphoneActive() { return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER); } } /** /** * Helper method on top of requestedCommunicationDevice() indicating if * Helper method on top of isDeviceRequestedForCommunication() indicating if * Bluetooth SCO ON is currently requested or not. * Bluetooth SCO ON is currently requested or not. * @return true if Bluetooth SCO ON is requested, false otherwise. * @return true if Bluetooth SCO ON is requested, false otherwise. */ */ /*package*/ boolean isBluetoothScoRequested() { /*package*/ boolean isBluetoothScoRequested() { synchronized (mDeviceStateLock) { return isDeviceRequestedForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO); AudioDeviceAttributes device = requestedCommunicationDevice(); } return device != null && device.getType() /** == AudioDeviceInfo.TYPE_BLUETOOTH_SCO; * Indicates if preferred route selection for communication is Bluetooth SCO. * @return true if Bluetooth SCO is preferred , false otherwise. */ /*package*/ boolean isBluetoothScoOn() { return isDeviceOnForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO); } } /*package*/ boolean isBluetoothScoActive() { return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO); } } /*package*/ void setWiredDeviceConnectionState(int type, /*package*/ void setWiredDeviceConnectionState(int type, Loading Loading @@ -593,18 +639,6 @@ import java.util.concurrent.atomic.AtomicBoolean; } } } } /** * Indicates if active route selection for communication is Bluetooth SCO. * @return true if Bluetooth SCO is active , false otherwise. */ /*package*/ boolean isBluetoothScoOn() { AudioDeviceAttributes device = getPreferredCommunicationDevice(); if (device == null) { return false; } return AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(device.getInternalType()); } /*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) { /*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) { synchronized (mDeviceStateLock) { synchronized (mDeviceStateLock) { return mDeviceInventory.startWatchingRoutes(observer); return mDeviceInventory.startWatchingRoutes(observer); Loading Loading @@ -748,8 +782,8 @@ import java.util.concurrent.atomic.AtomicBoolean; @GuardedBy("mDeviceStateLock") @GuardedBy("mDeviceStateLock") private void dispatchCommunicationDevice() { private void dispatchCommunicationDevice() { AudioDeviceInfo device = getCommunicationDevice(); int portId = (mActiveCommunicationDevice == null) ? 0 int portId = (device == null) ? 0 : device.getId(); : mActiveCommunicationDevice.getId(); if (portId == mCurCommunicationPortId) { if (portId == mCurCommunicationPortId) { return; return; } } Loading Loading @@ -1022,12 +1056,13 @@ import java.util.concurrent.atomic.AtomicBoolean; pw.println(" " + prefix + "pid: " + cl.getPid() + " device: " pw.println(" " + prefix + "pid: " + cl.getPid() + " device: " + cl.getDevice() + " cb: " + cl.getBinder()); }); + cl.getDevice() + " cb: " + cl.getBinder()); }); pw.println("\n" + prefix + "mPreferredCommunicationDevice: " pw.println("\n" + prefix + "Computed Preferred communication device: " + preferredCommunicationDevice()); pw.println("\n" + prefix + "Applied Preferred communication device: " + mPreferredCommunicationDevice); + mPreferredCommunicationDevice); pw.println(prefix + "Active communication device: " AudioDeviceInfo device = getCommunicationDevice(); + ((mActiveCommunicationDevice == null) ? "None" pw.println(prefix + "Selected Communication Device: " : new AudioDeviceAttributes(mActiveCommunicationDevice))); + ((device == null) ? "None" : new AudioDeviceAttributes(device))); pw.println(prefix + "mCommunicationStrategyId: " pw.println(prefix + "mCommunicationStrategyId: " + mCommunicationStrategyId); + mCommunicationStrategyId); Loading Loading @@ -1128,6 +1163,7 @@ import java.util.concurrent.atomic.AtomicBoolean; synchronized (mSetModeLock) { synchronized (mSetModeLock) { synchronized (mDeviceStateLock) { synchronized (mDeviceStateLock) { initCommunicationStrategyId(); initCommunicationStrategyId(); updateActiveCommunicationDevice(); mDeviceInventory.onRestoreDevices(); mDeviceInventory.onRestoreDevices(); mBtHelper.onAudioServerDiedRestoreA2dp(); mBtHelper.onAudioServerDiedRestoreA2dp(); onUpdateCommunicationRoute("MSG_RESTORE_DEVICES"); onUpdateCommunicationRoute("MSG_RESTORE_DEVICES"); Loading Loading @@ -1340,11 +1376,16 @@ import java.util.concurrent.atomic.AtomicBoolean; final List<AudioDeviceAttributes> devices = final List<AudioDeviceAttributes> devices = (List<AudioDeviceAttributes>) msg.obj; (List<AudioDeviceAttributes>) msg.obj; setPreferredDevicesForStrategySync(strategy, devices); setPreferredDevicesForStrategySync(strategy, devices); if (strategy == mCommunicationStrategyId) { onUpdatePhoneStrategyDevice(devices.isEmpty() ? null : devices.get(0)); } } break; } break; case MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY: { case MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY: { final int strategy = msg.arg1; final int strategy = msg.arg1; removePreferredDevicesForStrategySync(strategy); removePreferredDevicesForStrategySync(strategy); if (strategy == mCommunicationStrategyId) { onUpdatePhoneStrategyDevice(null); } } break; } break; case MSG_CHECK_MUTE_MUSIC: case MSG_CHECK_MUTE_MUSIC: checkMessagesMuteMusic(0); checkMessagesMuteMusic(0); Loading Loading @@ -1672,14 +1713,14 @@ import java.util.concurrent.atomic.AtomicBoolean; } } /** /** * Determines which forced usage for communication should be sent to audio policy manager * Determines which preferred device for phone strategy should be sent to audio policy manager * as a function of current SCO audio activation state and active communication route requests. * as a function of current SCO audio activation state and active communication route requests. * SCO audio state has the highest priority as it can result from external activation by * SCO audio state has the highest priority as it can result from external activation by * telephony service. * telephony service. * @return selected forced usage for communication. * @return selected forced usage for communication. */ */ @GuardedBy("mDeviceStateLock") @GuardedBy("mDeviceStateLock") @Nullable private AudioDeviceAttributes getPreferredCommunicationDevice() { @Nullable private AudioDeviceAttributes preferredCommunicationDevice() { boolean btSCoOn = mBluetoothScoOn && mBtHelper.isBluetoothScoOn(); boolean btSCoOn = mBluetoothScoOn && mBtHelper.isBluetoothScoOn(); if (btSCoOn) { if (btSCoOn) { // Use the SCO device known to BtHelper so that it matches exactly // Use the SCO device known to BtHelper so that it matches exactly Loading @@ -1692,8 +1733,7 @@ import java.util.concurrent.atomic.AtomicBoolean; } } } } AudioDeviceAttributes device = requestedCommunicationDevice(); AudioDeviceAttributes device = requestedCommunicationDevice(); if (device == null if (device == null || device.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_SCO) { || AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(device.getInternalType())) { // Do not indicate BT SCO selection if SCO is requested but SCO is not ON // Do not indicate BT SCO selection if SCO is requested but SCO is not ON return null; return null; } } Loading @@ -1707,31 +1747,50 @@ import java.util.concurrent.atomic.AtomicBoolean; // @GuardedBy("mSetModeLock") // @GuardedBy("mSetModeLock") @GuardedBy("mDeviceStateLock") @GuardedBy("mDeviceStateLock") private void onUpdateCommunicationRoute(String eventSource) { private void onUpdateCommunicationRoute(String eventSource) { mPreferredCommunicationDevice = getPreferredCommunicationDevice(); AudioDeviceAttributes preferredCommunicationDevice = preferredCommunicationDevice(); if (AudioService.DEBUG_COMM_RTE) { if (AudioService.DEBUG_COMM_RTE) { Log.v(TAG, "onUpdateCommunicationRoute, mPreferredCommunicationDevice: " Log.v(TAG, "onUpdateCommunicationRoute, preferredCommunicationDevice: " + mPreferredCommunicationDevice + " eventSource: " + eventSource); + preferredCommunicationDevice + " eventSource: " + eventSource); } } AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( "onUpdateCommunicationRoute, mPreferredCommunicationDevice: " "onUpdateCommunicationRoute, preferredCommunicationDevice: " + mPreferredCommunicationDevice + " eventSource: " + eventSource))); + preferredCommunicationDevice + " eventSource: " + eventSource))); if (mPreferredCommunicationDevice == null if (preferredCommunicationDevice == null || !AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains( || preferredCommunicationDevice.getType() != AudioDeviceInfo.TYPE_BLUETOOTH_SCO) { mPreferredCommunicationDevice.getInternalType())) { AudioSystem.setParameters("BT_SCO=off"); AudioSystem.setParameters("BT_SCO=off"); } else { } else { AudioSystem.setParameters("BT_SCO=on"); AudioSystem.setParameters("BT_SCO=on"); } } if (mPreferredCommunicationDevice == null) { if (preferredCommunicationDevice == null) { postRemovePreferredDevicesForStrategy(mCommunicationStrategyId); postRemovePreferredDevicesForStrategy(mCommunicationStrategyId); } else { } else { postSetPreferredDevicesForStrategy( postSetPreferredDevicesForStrategy( mCommunicationStrategyId, Arrays.asList(mPreferredCommunicationDevice)); mCommunicationStrategyId, Arrays.asList(preferredCommunicationDevice)); } } private void onUpdatePhoneStrategyDevice(AudioDeviceAttributes device) { synchronized (mSetModeLock) { synchronized (mDeviceStateLock) { boolean wasSpeakerphoneActive = isSpeakerphoneActive(); mPreferredCommunicationDevice = device; updateActiveCommunicationDevice(); if (wasSpeakerphoneActive != isSpeakerphoneActive()) { try { mContext.sendBroadcastAsUser( new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED) .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL); } catch (Exception e) { Log.w(TAG, "failed to broadcast ACTION_SPEAKERPHONE_STATE_CHANGED: " + e); } } } mAudioService.postUpdateRingerModeServiceInt(); mAudioService.postUpdateRingerModeServiceInt(); dispatchCommunicationDevice(); dispatchCommunicationDevice(); } } } } private CommunicationRouteClient removeCommunicationRouteClient( private CommunicationRouteClient removeCommunicationRouteClient( IBinder cb, boolean unregister) { IBinder cb, boolean unregister) { Loading services/core/java/com/android/server/audio/AudioService.java +3 −3 Original line number Original line Diff line number Diff line Loading @@ -4192,7 +4192,7 @@ public class AudioService extends IAudioService.Stub final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE || ringerMode == AudioManager.RINGER_MODE_SILENT; || ringerMode == AudioManager.RINGER_MODE_SILENT; final boolean shouldRingSco = ringerMode == AudioManager.RINGER_MODE_VIBRATE final boolean shouldRingSco = ringerMode == AudioManager.RINGER_MODE_VIBRATE && mDeviceBroker.isBluetoothScoOn(); && mDeviceBroker.isBluetoothScoActive(); // Ask audio policy engine to force use Bluetooth SCO channel if needed // Ask audio policy engine to force use Bluetooth SCO channel if needed final String eventSource = "muteRingerModeStreams() from u/pid:" + Binder.getCallingUid() final String eventSource = "muteRingerModeStreams() from u/pid:" + Binder.getCallingUid() + "/" + Binder.getCallingPid(); + "/" + Binder.getCallingPid(); Loading Loading @@ -5600,7 +5600,7 @@ public class AudioService extends IAudioService.Stub switch (mPlatformType) { switch (mPlatformType) { case AudioSystem.PLATFORM_VOICE: case AudioSystem.PLATFORM_VOICE: if (isInCommunication()) { if (isInCommunication()) { if (mDeviceBroker.isBluetoothScoOn()) { if (mDeviceBroker.isBluetoothScoActive()) { // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); return AudioSystem.STREAM_BLUETOOTH_SCO; return AudioSystem.STREAM_BLUETOOTH_SCO; } else { } else { Loading Loading @@ -5636,7 +5636,7 @@ public class AudioService extends IAudioService.Stub } } default: default: if (isInCommunication()) { if (isInCommunication()) { if (mDeviceBroker.isBluetoothScoOn()) { if (mDeviceBroker.isBluetoothScoActive()) { if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO"); if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO"); return AudioSystem.STREAM_BLUETOOTH_SCO; return AudioSystem.STREAM_BLUETOOTH_SCO; } else { } else { Loading Loading
services/core/java/com/android/server/audio/AudioDeviceBroker.java +145 −86 Original line number Original line Diff line number Diff line Loading @@ -80,9 +80,12 @@ import java.util.concurrent.atomic.AtomicBoolean; private final @NonNull AudioService mAudioService; private final @NonNull AudioService mAudioService; private final @NonNull Context mContext; private final @NonNull Context mContext; /** Forced device usage for communications sent to AudioSystem */ /** ID for Communication strategy retrieved form audio policy manager */ private AudioDeviceAttributes mPreferredCommunicationDevice; private int mCommunicationStrategyId = -1; private int mCommunicationStrategyId = -1; /** Active communication device reported by audio policy manager */ private AudioDeviceInfo mActiveCommunicationDevice; /** Last preferred device set for communication strategy */ private AudioDeviceAttributes mPreferredCommunicationDevice; // Manages all connected devices, only ever accessed on the message loop // Manages all connected devices, only ever accessed on the message loop private final AudioDeviceInventory mDeviceInventory; private final AudioDeviceInventory mDeviceInventory; Loading Loading @@ -153,8 +156,9 @@ import java.util.concurrent.atomic.AtomicBoolean; private void init() { private void init() { setupMessaging(mContext); setupMessaging(mContext); mPreferredCommunicationDevice = null; initCommunicationStrategyId(); initCommunicationStrategyId(); mPreferredCommunicationDevice = null; updateActiveCommunicationDevice(); mSystemServer.registerUserStartedReceiver(mContext); mSystemServer.registerUserStartedReceiver(mContext); } } Loading Loading @@ -300,7 +304,6 @@ import java.util.concurrent.atomic.AtomicBoolean; + " from API: " + eventSource)).printLog(TAG)); + " from API: " + eventSource)).printLog(TAG)); final boolean wasBtScoRequested = isBluetoothScoRequested(); final boolean wasBtScoRequested = isBluetoothScoRequested(); final boolean wasSpeakerphoneRequested = isSpeakerphoneRequested(); CommunicationRouteClient client; CommunicationRouteClient client; Loading Loading @@ -341,16 +344,6 @@ import java.util.concurrent.atomic.AtomicBoolean; mBtHelper.stopBluetoothSco(eventSource); mBtHelper.stopBluetoothSco(eventSource); } } if (wasSpeakerphoneRequested != isSpeakerphoneRequested()) { try { mContext.sendBroadcastAsUser( new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED) .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL); } catch (Exception e) { Log.w(TAG, "failed to broadcast ACTION_SPEAKERPHONE_STATE_CHANGED: " + e); } } sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE, SENDMSG_QUEUE, eventSource); sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE, SENDMSG_QUEUE, eventSource); } } Loading Loading @@ -386,9 +379,19 @@ import java.util.concurrent.atomic.AtomicBoolean; * Returns the device currently requested for communication use case. * Returns the device currently requested for communication use case. * @return AudioDeviceInfo the requested device for communication. * @return AudioDeviceInfo the requested device for communication. */ */ AudioDeviceInfo getCommunicationDevice() { /* package */ AudioDeviceInfo getCommunicationDevice() { synchronized (mDeviceStateLock) { synchronized (mDeviceStateLock) { AudioDeviceAttributes device = requestedCommunicationDevice(); updateActiveCommunicationDevice(); return mActiveCommunicationDevice; } } /** * Updates currently active communication device (mActiveCommunicationDevice). */ @GuardedBy("mDeviceStateLock") void updateActiveCommunicationDevice() { AudioDeviceAttributes device = preferredCommunicationDevice(); if (device == null) { if (device == null) { AudioAttributes attr = AudioAttributes attr = AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType( AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType( Loading @@ -396,56 +399,99 @@ import java.util.concurrent.atomic.AtomicBoolean; List<AudioDeviceAttributes> devices = AudioSystem.getDevicesForAttributes(attr); List<AudioDeviceAttributes> devices = AudioSystem.getDevicesForAttributes(attr); if (devices.isEmpty()) { if (devices.isEmpty()) { if (mAudioService.isPlatformVoice()) { if (mAudioService.isPlatformVoice()) { Log.w(TAG, "getCommunicationDevice(): no device for phone strategy"); Log.w(TAG, "updateActiveCommunicationDevice(): no device for phone strategy"); } } return null; mActiveCommunicationDevice = null; return; } } device = devices.get(0); device = devices.get(0); } } return AudioManager.getDeviceInfoFromTypeAndAddress( mActiveCommunicationDevice = AudioManager.getDeviceInfoFromTypeAndAddress( device.getType(), device.getAddress()); device.getType(), device.getAddress()); } } /** * Indicates if the device which type is passed as argument is currently resquested to be used * for communication. * @param deviceType the device type the query applies to. * @return true if this device type is requested for communication. */ private boolean isDeviceRequestedForCommunication(int deviceType) { synchronized (mDeviceStateLock) { AudioDeviceAttributes device = requestedCommunicationDevice(); return device != null && device.getType() == deviceType; } } /** * Indicates if the device which type is passed as argument is currently either resquested * to be used for communication or selected for an other reason (e.g bluetooth SCO audio * is active for SCO device). * @param deviceType the device type the query applies to. * @return true if this device type is requested for communication. */ private boolean isDeviceOnForCommunication(int deviceType) { synchronized (mDeviceStateLock) { AudioDeviceAttributes device = preferredCommunicationDevice(); return device != null && device.getType() == deviceType; } } /** * Indicates if the device which type is passed as argument is active for communication. * Active means not only currently used by audio policy manager for communication strategy * but also explicitly requested for use by communication strategy. * @param deviceType the device type the query applies to. * @return true if this device type is requested for communication. */ private boolean isDeviceActiveForCommunication(int deviceType) { return mActiveCommunicationDevice != null && mActiveCommunicationDevice.getType() == deviceType && mPreferredCommunicationDevice != null && mPreferredCommunicationDevice.getType() == deviceType; } } /** /** * Helper method on top of requestedCommunicationDevice() indicating if * Helper method on top of isDeviceRequestedForCommunication() indicating if * speakerphone ON is currently requested or not. * speakerphone ON is currently requested or not. * @return true if speakerphone ON requested, false otherwise. * @return true if speakerphone ON requested, false otherwise. */ */ private boolean isSpeakerphoneRequested() { private boolean isSpeakerphoneRequested() { synchronized (mDeviceStateLock) { return isDeviceRequestedForCommunication(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER); AudioDeviceAttributes device = requestedCommunicationDevice(); return device != null && device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER; } } } /** /** * Indicates if active route selection for communication is speakerphone. * Indicates if preferred route selection for communication is speakerphone. * @return true if speakerphone is active, false otherwise. * @return true if speakerphone is active, false otherwise. */ */ /*package*/ boolean isSpeakerphoneOn() { /*package*/ boolean isSpeakerphoneOn() { AudioDeviceAttributes device = getPreferredCommunicationDevice(); return isDeviceOnForCommunication(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER); if (device == null) { return false; } } return device.getInternalType() == AudioSystem.DEVICE_OUT_SPEAKER; private boolean isSpeakerphoneActive() { return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER); } } /** /** * Helper method on top of requestedCommunicationDevice() indicating if * Helper method on top of isDeviceRequestedForCommunication() indicating if * Bluetooth SCO ON is currently requested or not. * Bluetooth SCO ON is currently requested or not. * @return true if Bluetooth SCO ON is requested, false otherwise. * @return true if Bluetooth SCO ON is requested, false otherwise. */ */ /*package*/ boolean isBluetoothScoRequested() { /*package*/ boolean isBluetoothScoRequested() { synchronized (mDeviceStateLock) { return isDeviceRequestedForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO); AudioDeviceAttributes device = requestedCommunicationDevice(); } return device != null && device.getType() /** == AudioDeviceInfo.TYPE_BLUETOOTH_SCO; * Indicates if preferred route selection for communication is Bluetooth SCO. * @return true if Bluetooth SCO is preferred , false otherwise. */ /*package*/ boolean isBluetoothScoOn() { return isDeviceOnForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO); } } /*package*/ boolean isBluetoothScoActive() { return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO); } } /*package*/ void setWiredDeviceConnectionState(int type, /*package*/ void setWiredDeviceConnectionState(int type, Loading Loading @@ -593,18 +639,6 @@ import java.util.concurrent.atomic.AtomicBoolean; } } } } /** * Indicates if active route selection for communication is Bluetooth SCO. * @return true if Bluetooth SCO is active , false otherwise. */ /*package*/ boolean isBluetoothScoOn() { AudioDeviceAttributes device = getPreferredCommunicationDevice(); if (device == null) { return false; } return AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(device.getInternalType()); } /*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) { /*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) { synchronized (mDeviceStateLock) { synchronized (mDeviceStateLock) { return mDeviceInventory.startWatchingRoutes(observer); return mDeviceInventory.startWatchingRoutes(observer); Loading Loading @@ -748,8 +782,8 @@ import java.util.concurrent.atomic.AtomicBoolean; @GuardedBy("mDeviceStateLock") @GuardedBy("mDeviceStateLock") private void dispatchCommunicationDevice() { private void dispatchCommunicationDevice() { AudioDeviceInfo device = getCommunicationDevice(); int portId = (mActiveCommunicationDevice == null) ? 0 int portId = (device == null) ? 0 : device.getId(); : mActiveCommunicationDevice.getId(); if (portId == mCurCommunicationPortId) { if (portId == mCurCommunicationPortId) { return; return; } } Loading Loading @@ -1022,12 +1056,13 @@ import java.util.concurrent.atomic.AtomicBoolean; pw.println(" " + prefix + "pid: " + cl.getPid() + " device: " pw.println(" " + prefix + "pid: " + cl.getPid() + " device: " + cl.getDevice() + " cb: " + cl.getBinder()); }); + cl.getDevice() + " cb: " + cl.getBinder()); }); pw.println("\n" + prefix + "mPreferredCommunicationDevice: " pw.println("\n" + prefix + "Computed Preferred communication device: " + preferredCommunicationDevice()); pw.println("\n" + prefix + "Applied Preferred communication device: " + mPreferredCommunicationDevice); + mPreferredCommunicationDevice); pw.println(prefix + "Active communication device: " AudioDeviceInfo device = getCommunicationDevice(); + ((mActiveCommunicationDevice == null) ? "None" pw.println(prefix + "Selected Communication Device: " : new AudioDeviceAttributes(mActiveCommunicationDevice))); + ((device == null) ? "None" : new AudioDeviceAttributes(device))); pw.println(prefix + "mCommunicationStrategyId: " pw.println(prefix + "mCommunicationStrategyId: " + mCommunicationStrategyId); + mCommunicationStrategyId); Loading Loading @@ -1128,6 +1163,7 @@ import java.util.concurrent.atomic.AtomicBoolean; synchronized (mSetModeLock) { synchronized (mSetModeLock) { synchronized (mDeviceStateLock) { synchronized (mDeviceStateLock) { initCommunicationStrategyId(); initCommunicationStrategyId(); updateActiveCommunicationDevice(); mDeviceInventory.onRestoreDevices(); mDeviceInventory.onRestoreDevices(); mBtHelper.onAudioServerDiedRestoreA2dp(); mBtHelper.onAudioServerDiedRestoreA2dp(); onUpdateCommunicationRoute("MSG_RESTORE_DEVICES"); onUpdateCommunicationRoute("MSG_RESTORE_DEVICES"); Loading Loading @@ -1340,11 +1376,16 @@ import java.util.concurrent.atomic.AtomicBoolean; final List<AudioDeviceAttributes> devices = final List<AudioDeviceAttributes> devices = (List<AudioDeviceAttributes>) msg.obj; (List<AudioDeviceAttributes>) msg.obj; setPreferredDevicesForStrategySync(strategy, devices); setPreferredDevicesForStrategySync(strategy, devices); if (strategy == mCommunicationStrategyId) { onUpdatePhoneStrategyDevice(devices.isEmpty() ? null : devices.get(0)); } } break; } break; case MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY: { case MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY: { final int strategy = msg.arg1; final int strategy = msg.arg1; removePreferredDevicesForStrategySync(strategy); removePreferredDevicesForStrategySync(strategy); if (strategy == mCommunicationStrategyId) { onUpdatePhoneStrategyDevice(null); } } break; } break; case MSG_CHECK_MUTE_MUSIC: case MSG_CHECK_MUTE_MUSIC: checkMessagesMuteMusic(0); checkMessagesMuteMusic(0); Loading Loading @@ -1672,14 +1713,14 @@ import java.util.concurrent.atomic.AtomicBoolean; } } /** /** * Determines which forced usage for communication should be sent to audio policy manager * Determines which preferred device for phone strategy should be sent to audio policy manager * as a function of current SCO audio activation state and active communication route requests. * as a function of current SCO audio activation state and active communication route requests. * SCO audio state has the highest priority as it can result from external activation by * SCO audio state has the highest priority as it can result from external activation by * telephony service. * telephony service. * @return selected forced usage for communication. * @return selected forced usage for communication. */ */ @GuardedBy("mDeviceStateLock") @GuardedBy("mDeviceStateLock") @Nullable private AudioDeviceAttributes getPreferredCommunicationDevice() { @Nullable private AudioDeviceAttributes preferredCommunicationDevice() { boolean btSCoOn = mBluetoothScoOn && mBtHelper.isBluetoothScoOn(); boolean btSCoOn = mBluetoothScoOn && mBtHelper.isBluetoothScoOn(); if (btSCoOn) { if (btSCoOn) { // Use the SCO device known to BtHelper so that it matches exactly // Use the SCO device known to BtHelper so that it matches exactly Loading @@ -1692,8 +1733,7 @@ import java.util.concurrent.atomic.AtomicBoolean; } } } } AudioDeviceAttributes device = requestedCommunicationDevice(); AudioDeviceAttributes device = requestedCommunicationDevice(); if (device == null if (device == null || device.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_SCO) { || AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(device.getInternalType())) { // Do not indicate BT SCO selection if SCO is requested but SCO is not ON // Do not indicate BT SCO selection if SCO is requested but SCO is not ON return null; return null; } } Loading @@ -1707,31 +1747,50 @@ import java.util.concurrent.atomic.AtomicBoolean; // @GuardedBy("mSetModeLock") // @GuardedBy("mSetModeLock") @GuardedBy("mDeviceStateLock") @GuardedBy("mDeviceStateLock") private void onUpdateCommunicationRoute(String eventSource) { private void onUpdateCommunicationRoute(String eventSource) { mPreferredCommunicationDevice = getPreferredCommunicationDevice(); AudioDeviceAttributes preferredCommunicationDevice = preferredCommunicationDevice(); if (AudioService.DEBUG_COMM_RTE) { if (AudioService.DEBUG_COMM_RTE) { Log.v(TAG, "onUpdateCommunicationRoute, mPreferredCommunicationDevice: " Log.v(TAG, "onUpdateCommunicationRoute, preferredCommunicationDevice: " + mPreferredCommunicationDevice + " eventSource: " + eventSource); + preferredCommunicationDevice + " eventSource: " + eventSource); } } AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( "onUpdateCommunicationRoute, mPreferredCommunicationDevice: " "onUpdateCommunicationRoute, preferredCommunicationDevice: " + mPreferredCommunicationDevice + " eventSource: " + eventSource))); + preferredCommunicationDevice + " eventSource: " + eventSource))); if (mPreferredCommunicationDevice == null if (preferredCommunicationDevice == null || !AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains( || preferredCommunicationDevice.getType() != AudioDeviceInfo.TYPE_BLUETOOTH_SCO) { mPreferredCommunicationDevice.getInternalType())) { AudioSystem.setParameters("BT_SCO=off"); AudioSystem.setParameters("BT_SCO=off"); } else { } else { AudioSystem.setParameters("BT_SCO=on"); AudioSystem.setParameters("BT_SCO=on"); } } if (mPreferredCommunicationDevice == null) { if (preferredCommunicationDevice == null) { postRemovePreferredDevicesForStrategy(mCommunicationStrategyId); postRemovePreferredDevicesForStrategy(mCommunicationStrategyId); } else { } else { postSetPreferredDevicesForStrategy( postSetPreferredDevicesForStrategy( mCommunicationStrategyId, Arrays.asList(mPreferredCommunicationDevice)); mCommunicationStrategyId, Arrays.asList(preferredCommunicationDevice)); } } private void onUpdatePhoneStrategyDevice(AudioDeviceAttributes device) { synchronized (mSetModeLock) { synchronized (mDeviceStateLock) { boolean wasSpeakerphoneActive = isSpeakerphoneActive(); mPreferredCommunicationDevice = device; updateActiveCommunicationDevice(); if (wasSpeakerphoneActive != isSpeakerphoneActive()) { try { mContext.sendBroadcastAsUser( new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED) .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL); } catch (Exception e) { Log.w(TAG, "failed to broadcast ACTION_SPEAKERPHONE_STATE_CHANGED: " + e); } } } mAudioService.postUpdateRingerModeServiceInt(); mAudioService.postUpdateRingerModeServiceInt(); dispatchCommunicationDevice(); dispatchCommunicationDevice(); } } } } private CommunicationRouteClient removeCommunicationRouteClient( private CommunicationRouteClient removeCommunicationRouteClient( IBinder cb, boolean unregister) { IBinder cb, boolean unregister) { Loading
services/core/java/com/android/server/audio/AudioService.java +3 −3 Original line number Original line Diff line number Diff line Loading @@ -4192,7 +4192,7 @@ public class AudioService extends IAudioService.Stub final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE || ringerMode == AudioManager.RINGER_MODE_SILENT; || ringerMode == AudioManager.RINGER_MODE_SILENT; final boolean shouldRingSco = ringerMode == AudioManager.RINGER_MODE_VIBRATE final boolean shouldRingSco = ringerMode == AudioManager.RINGER_MODE_VIBRATE && mDeviceBroker.isBluetoothScoOn(); && mDeviceBroker.isBluetoothScoActive(); // Ask audio policy engine to force use Bluetooth SCO channel if needed // Ask audio policy engine to force use Bluetooth SCO channel if needed final String eventSource = "muteRingerModeStreams() from u/pid:" + Binder.getCallingUid() final String eventSource = "muteRingerModeStreams() from u/pid:" + Binder.getCallingUid() + "/" + Binder.getCallingPid(); + "/" + Binder.getCallingPid(); Loading Loading @@ -5600,7 +5600,7 @@ public class AudioService extends IAudioService.Stub switch (mPlatformType) { switch (mPlatformType) { case AudioSystem.PLATFORM_VOICE: case AudioSystem.PLATFORM_VOICE: if (isInCommunication()) { if (isInCommunication()) { if (mDeviceBroker.isBluetoothScoOn()) { if (mDeviceBroker.isBluetoothScoActive()) { // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); return AudioSystem.STREAM_BLUETOOTH_SCO; return AudioSystem.STREAM_BLUETOOTH_SCO; } else { } else { Loading Loading @@ -5636,7 +5636,7 @@ public class AudioService extends IAudioService.Stub } } default: default: if (isInCommunication()) { if (isInCommunication()) { if (mDeviceBroker.isBluetoothScoOn()) { if (mDeviceBroker.isBluetoothScoActive()) { if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO"); if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO"); return AudioSystem.STREAM_BLUETOOTH_SCO; return AudioSystem.STREAM_BLUETOOTH_SCO; } else { } else { Loading