diff options
| -rw-r--r-- | services/core/java/com/android/server/audio/AudioDeviceBroker.java | 207 |
1 files changed, 105 insertions, 102 deletions
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index bbffc894ef3e..2fe06094bd88 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -286,22 +286,9 @@ import java.util.concurrent.atomic.AtomicBoolean; if (AudioService.DEBUG_COMM_RTE) { Log.v(TAG, "setSpeakerphoneOn, on: " + on + " pid: " + pid); } - - synchronized (mSetModeLock) { - synchronized (mDeviceStateLock) { - AudioDeviceAttributes device = null; - if (on) { - device = new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, ""); - } else { - CommunicationRouteClient client = getCommunicationRouteClientForPid(pid); - if (client == null || !client.requestsSpeakerphone()) { - return; - } - } - postSetCommunicationRouteForClient(new CommunicationClientInfo( - cb, pid, device, BtHelper.SCO_MODE_UNDEFINED, eventSource)); - } - } + postSetCommunicationDeviceForClient(new CommunicationDeviceInfo( + cb, pid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, ""), + on, BtHelper.SCO_MODE_UNDEFINED, eventSource, false)); } /** @@ -311,6 +298,9 @@ import java.util.concurrent.atomic.AtomicBoolean; * @param device Device selected or null to unselect. * @param eventSource for logging purposes */ + + private static final long SET_COMMUNICATION_DEVICE_TIMEOUT_MS = 3000; + /*package*/ boolean setCommunicationDevice( IBinder cb, int pid, AudioDeviceInfo device, String eventSource) { @@ -318,21 +308,53 @@ import java.util.concurrent.atomic.AtomicBoolean; Log.v(TAG, "setCommunicationDevice, device: " + device + ", pid: " + pid); } - synchronized (mSetModeLock) { - synchronized (mDeviceStateLock) { - AudioDeviceAttributes deviceAttr = null; - if (device != null) { - deviceAttr = new AudioDeviceAttributes(device); - } else { - CommunicationRouteClient client = getCommunicationRouteClientForPid(pid); - if (client == null) { - return false; + AudioDeviceAttributes deviceAttr = + (device != null) ? new AudioDeviceAttributes(device) : null; + CommunicationDeviceInfo deviceInfo = new CommunicationDeviceInfo(cb, pid, deviceAttr, + device != null, BtHelper.SCO_MODE_UNDEFINED, eventSource, true); + postSetCommunicationDeviceForClient(deviceInfo); + boolean status; + synchronized (deviceInfo) { + final long start = System.currentTimeMillis(); + long elapsed = 0; + while (deviceInfo.mWaitForStatus) { + try { + deviceInfo.wait(SET_COMMUNICATION_DEVICE_TIMEOUT_MS - elapsed); + } catch (InterruptedException e) { + elapsed = System.currentTimeMillis() - start; + if (elapsed >= SET_COMMUNICATION_DEVICE_TIMEOUT_MS) { + deviceInfo.mStatus = false; + deviceInfo.mWaitForStatus = false; } } - postSetCommunicationRouteForClient(new CommunicationClientInfo( - cb, pid, deviceAttr, BtHelper.SCO_MODE_UNDEFINED, eventSource)); } + status = deviceInfo.mStatus; } + return status; + } + + /** + * 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*/ boolean onSetCommunicationDeviceForClient(CommunicationDeviceInfo deviceInfo) { + if (AudioService.DEBUG_COMM_RTE) { + Log.v(TAG, "onSetCommunicationDeviceForClient: " + deviceInfo); + } + if (!deviceInfo.mOn) { + CommunicationRouteClient client = getCommunicationRouteClientForPid(deviceInfo.mPid); + if (client == null || (deviceInfo.mDevice != null + && !deviceInfo.mDevice.equals(client.getDevice()))) { + return false; + } + } + + AudioDeviceAttributes device = deviceInfo.mOn ? deviceInfo.mDevice : null; + setCommunicationRouteForClient(deviceInfo.mCb, deviceInfo.mPid, device, + deviceInfo.mScoAudioMode, deviceInfo.mEventSource); return true; } @@ -390,7 +412,7 @@ import java.util.concurrent.atomic.AtomicBoolean; mBtHelper.stopBluetoothSco(eventSource); } - sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE, SENDMSG_QUEUE, eventSource); + updateCommunicationRoute(eventSource); } /** @@ -424,7 +446,7 @@ import java.util.concurrent.atomic.AtomicBoolean; CommunicationRouteClient crc = topCommunicationRouteClient(); AudioDeviceAttributes device = crc != null ? crc.getDevice() : null; if (AudioService.DEBUG_COMM_RTE) { - Log.v(TAG, "requestedCommunicationDevice, device: " + Log.v(TAG, "requestedCommunicationDevice: " + device + " mAudioModeOwner: " + mAudioModeOwner.toString()); } return device; @@ -822,37 +844,22 @@ import java.util.concurrent.atomic.AtomicBoolean; @NonNull String eventSource) { if (AudioService.DEBUG_COMM_RTE) { - Log.v(TAG, "startBluetoothScoForClient_Sync, pid: " + pid); - } - - synchronized (mSetModeLock) { - synchronized (mDeviceStateLock) { - AudioDeviceAttributes device = - new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""); - - postSetCommunicationRouteForClient(new CommunicationClientInfo( - cb, pid, device, scoAudioMode, eventSource)); - } + Log.v(TAG, "startBluetoothScoForClient, pid: " + pid); } + postSetCommunicationDeviceForClient(new CommunicationDeviceInfo( + cb, pid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""), + true, scoAudioMode, eventSource, false)); } /*package*/ void stopBluetoothScoForClient( IBinder cb, int pid, @NonNull String eventSource) { if (AudioService.DEBUG_COMM_RTE) { - Log.v(TAG, "stopBluetoothScoForClient_Sync, pid: " + pid); - } - - synchronized (mSetModeLock) { - synchronized (mDeviceStateLock) { - CommunicationRouteClient client = getCommunicationRouteClientForPid(pid); - if (client == null || !client.requestsBluetoothSco()) { - return; - } - postSetCommunicationRouteForClient(new CommunicationClientInfo( - cb, pid, null, BtHelper.SCO_MODE_UNDEFINED, eventSource)); - } + Log.v(TAG, "stopBluetoothScoForClient, pid: " + pid); } + postSetCommunicationDeviceForClient(new CommunicationDeviceInfo( + cb, pid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""), + false, BtHelper.SCO_MODE_UNDEFINED, eventSource, false)); } /*package*/ int setPreferredDevicesForStrategySync(int strategy, @@ -990,7 +997,8 @@ import java.util.concurrent.atomic.AtomicBoolean; } //--------------------------------------------------------------------- - // Message handling on behalf of helper classes + // Message handling on behalf of helper classes. + // Each of these methods posts a message to mBrokerHandler message queue. /*package*/ void postBroadcastScoConnectionState(int state) { sendIMsgNoDelay(MSG_I_BROADCAST_BT_CONNECTION_STATE, SENDMSG_QUEUE, state); } @@ -1046,28 +1054,34 @@ import java.util.concurrent.atomic.AtomicBoolean; sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT, SENDMSG_QUEUE, eventSource); } - /*package*/ void postSetCommunicationRouteForClient(CommunicationClientInfo info) { - sendLMsgNoDelay(MSG_L_SET_COMMUNICATION_ROUTE_FOR_CLIENT, SENDMSG_QUEUE, info); + /*package*/ void postSetCommunicationDeviceForClient(CommunicationDeviceInfo info) { + sendLMsgNoDelay(MSG_L_SET_COMMUNICATION_DEVICE_FOR_CLIENT, SENDMSG_QUEUE, info); } /*package*/ void postScoAudioStateChanged(int state) { sendIMsgNoDelay(MSG_I_SCO_AUDIO_STATE_CHANGED, SENDMSG_QUEUE, state); } - /*package*/ static final class CommunicationClientInfo { - final @NonNull IBinder mCb; - final int mPid; - final @NonNull AudioDeviceAttributes mDevice; - final int mScoAudioMode; - final @NonNull String mEventSource; + /*package*/ static final class CommunicationDeviceInfo { + final @NonNull IBinder mCb; // Identifies the requesting client for death handler + final int mPid; // Requester process ID + final @Nullable AudioDeviceAttributes mDevice; // Device being set or reset. + final boolean mOn; // true if setting, false if resetting + final int mScoAudioMode; // only used for SCO: requested audio mode + final @NonNull String mEventSource; // caller identifier for logging + boolean mWaitForStatus; // true if the caller waits for a completion status (API dependent) + boolean mStatus = false; // completion status only used if mWaitForStatus is true - CommunicationClientInfo(@NonNull IBinder cb, int pid, @NonNull AudioDeviceAttributes device, - int scoAudioMode, @NonNull String eventSource) { + CommunicationDeviceInfo(@NonNull IBinder cb, int pid, + @Nullable AudioDeviceAttributes device, boolean on, int scoAudioMode, + @NonNull String eventSource, boolean waitForStatus) { mCb = cb; mPid = pid; mDevice = device; + mOn = on; mScoAudioMode = scoAudioMode; mEventSource = eventSource; + mWaitForStatus = waitForStatus; } // redefine equality op so we can match messages intended for this client @@ -1079,21 +1093,24 @@ import java.util.concurrent.atomic.AtomicBoolean; if (this == o) { return true; } - if (!(o instanceof CommunicationClientInfo)) { + if (!(o instanceof CommunicationDeviceInfo)) { return false; } - return mCb.equals(((CommunicationClientInfo) o).mCb) - && mPid == ((CommunicationClientInfo) o).mPid; + return mCb.equals(((CommunicationDeviceInfo) o).mCb) + && mPid == ((CommunicationDeviceInfo) o).mPid; } @Override public String toString() { - return "CommunicationClientInfo mCb=" + mCb.toString() - +"mPid=" + mPid - +"mDevice=" + mDevice.toString() - +"mScoAudioMode=" + mScoAudioMode - +"mEventSource=" + mEventSource; + return "CommunicationDeviceInfo mCb=" + mCb.toString() + + " mPid=" + mPid + + " mDevice=[" + (mDevice != null ? mDevice.toString() : "null") + "]" + + " mOn=" + mOn + + " mScoAudioMode=" + mScoAudioMode + + " mEventSource=" + mEventSource + + " mWaitForStatus=" + mWaitForStatus + + " mStatus=" + mStatus; } } @@ -1297,7 +1314,7 @@ import java.util.concurrent.atomic.AtomicBoolean; updateActiveCommunicationDevice(); mDeviceInventory.onRestoreDevices(); mBtHelper.onAudioServerDiedRestoreA2dp(); - onUpdateCommunicationRoute("MSG_RESTORE_DEVICES"); + updateCommunicationRoute("MSG_RESTORE_DEVICES"); } } break; @@ -1392,28 +1409,27 @@ import java.util.concurrent.atomic.AtomicBoolean; } break; - case MSG_L_SET_COMMUNICATION_ROUTE_FOR_CLIENT: + case MSG_L_SET_COMMUNICATION_DEVICE_FOR_CLIENT: + CommunicationDeviceInfo deviceInfo = (CommunicationDeviceInfo) msg.obj; + boolean status; synchronized (mSetModeLock) { synchronized (mDeviceStateLock) { - CommunicationClientInfo info = (CommunicationClientInfo) msg.obj; - setCommunicationRouteForClient(info.mCb, info.mPid, info.mDevice, - info.mScoAudioMode, info.mEventSource); + status = onSetCommunicationDeviceForClient(deviceInfo); } } - break; - - case MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT: - synchronized (mSetModeLock) { - synchronized (mDeviceStateLock) { - onUpdateCommunicationRouteClient((String) msg.obj); + synchronized (deviceInfo) { + if (deviceInfo.mWaitForStatus) { + deviceInfo.mStatus = status; + deviceInfo.mWaitForStatus = false; + deviceInfo.notify(); } } break; - case MSG_L_UPDATE_COMMUNICATION_ROUTE: + case MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT: synchronized (mSetModeLock) { synchronized (mDeviceStateLock) { - onUpdateCommunicationRoute((String) msg.obj); + onUpdateCommunicationRouteClient((String) msg.obj); } } break; @@ -1568,8 +1584,7 @@ import java.util.concurrent.atomic.AtomicBoolean; private static final int MSG_IL_SAVE_PREF_DEVICES_FOR_CAPTURE_PRESET = 37; private static final int MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET = 38; - private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE = 39; - private static final int MSG_L_SET_COMMUNICATION_ROUTE_FOR_CLIENT = 42; + private static final int MSG_L_SET_COMMUNICATION_DEVICE_FOR_CLIENT = 42; private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT = 43; private static final int MSG_I_SCO_AUDIO_STATE_CHANGED = 44; @@ -1793,18 +1808,6 @@ import java.util.concurrent.atomic.AtomicBoolean; AudioDeviceAttributes getDevice() { return mDevice; } - - boolean requestsBluetoothSco() { - return mDevice != null - && mDevice.getType() - == AudioDeviceInfo.TYPE_BLUETOOTH_SCO; - } - - boolean requestsSpeakerphone() { - return mDevice != null - && mDevice.getType() - == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER; - } } // @GuardedBy("mSetModeLock") @@ -1852,14 +1855,14 @@ import java.util.concurrent.atomic.AtomicBoolean; */ // @GuardedBy("mSetModeLock") @GuardedBy("mDeviceStateLock") - private void onUpdateCommunicationRoute(String eventSource) { + private void updateCommunicationRoute(String eventSource) { AudioDeviceAttributes preferredCommunicationDevice = preferredCommunicationDevice(); if (AudioService.DEBUG_COMM_RTE) { - Log.v(TAG, "onUpdateCommunicationRoute, preferredCommunicationDevice: " + Log.v(TAG, "updateCommunicationRoute, preferredCommunicationDevice: " + preferredCommunicationDevice + " eventSource: " + eventSource); } AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( - "onUpdateCommunicationRoute, preferredCommunicationDevice: " + "updateCommunicationRoute, preferredCommunicationDevice: " + preferredCommunicationDevice + " eventSource: " + eventSource))); if (preferredCommunicationDevice == null @@ -1895,7 +1898,7 @@ import java.util.concurrent.atomic.AtomicBoolean; // @GuardedBy("mSetModeLock") @GuardedBy("mDeviceStateLock") private void onUpdateCommunicationRouteClient(String eventSource) { - onUpdateCommunicationRoute(eventSource); + updateCommunicationRoute(eventSource); CommunicationRouteClient crc = topCommunicationRouteClient(); if (AudioService.DEBUG_COMM_RTE) { Log.v(TAG, "onUpdateCommunicationRouteClient, crc: " |