Merge "AudioDeviceBroker: strengthen setcommunicationDevice implementation"
This commit is contained in:
@@ -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,12 +1409,19 @@ 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);
|
||||
}
|
||||
}
|
||||
synchronized (deviceInfo) {
|
||||
if (deviceInfo.mWaitForStatus) {
|
||||
deviceInfo.mStatus = status;
|
||||
deviceInfo.mWaitForStatus = false;
|
||||
deviceInfo.notify();
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1410,14 +1434,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
}
|
||||
break;
|
||||
|
||||
case MSG_L_UPDATE_COMMUNICATION_ROUTE:
|
||||
synchronized (mSetModeLock) {
|
||||
synchronized (mDeviceStateLock) {
|
||||
onUpdateCommunicationRoute((String) msg.obj);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED:
|
||||
synchronized (mSetModeLock) {
|
||||
synchronized (mDeviceStateLock) {
|
||||
@@ -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: "
|
||||
|
||||
Reference in New Issue
Block a user