Merge "audioservice: improve SCO audio control logic" into sc-v2-dev
This commit is contained in:
@@ -252,8 +252,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setCommunicationRouteForClient(
|
postSetCommunicationRouteForClient(new CommunicationClientInfo(
|
||||||
cb, pid, device, BtHelper.SCO_MODE_UNDEFINED, eventSource);
|
cb, pid, device, BtHelper.SCO_MODE_UNDEFINED, eventSource));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -283,8 +283,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setCommunicationRouteForClient(
|
postSetCommunicationRouteForClient(new CommunicationClientInfo(
|
||||||
cb, pid, deviceAttr, BtHelper.SCO_MODE_UNDEFINED, eventSource);
|
cb, pid, deviceAttr, BtHelper.SCO_MODE_UNDEFINED, eventSource));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -348,26 +348,35 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the device currently requested for communication use case.
|
* Returns the communication client with the highest priority:
|
||||||
* If the current audio mode owner is in the communication route client list,
|
* - 1) the client which is currently also controlling the audio mode
|
||||||
* use this preference.
|
* - 2) the first client in the stack if there is no audio mode owner
|
||||||
* Otherwise use first client's preference (first client corresponds to latest request).
|
* - 3) no client otherwise
|
||||||
* null is returned if no client is in the list.
|
* @return CommunicationRouteClient the client driving the communication use case routing.
|
||||||
* @return AudioDeviceAttributes the requested device for communication.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@GuardedBy("mDeviceStateLock")
|
@GuardedBy("mDeviceStateLock")
|
||||||
private AudioDeviceAttributes requestedCommunicationDevice() {
|
private CommunicationRouteClient topCommunicationRouteClient() {
|
||||||
AudioDeviceAttributes device = null;
|
for (CommunicationRouteClient crc : mCommunicationRouteClients) {
|
||||||
for (CommunicationRouteClient cl : mCommunicationRouteClients) {
|
if (crc.getPid() == mModeOwnerPid) {
|
||||||
if (cl.getPid() == mModeOwnerPid) {
|
return crc;
|
||||||
device = cl.getDevice();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!mCommunicationRouteClients.isEmpty() && mModeOwnerPid == 0) {
|
if (!mCommunicationRouteClients.isEmpty() && mModeOwnerPid == 0) {
|
||||||
device = mCommunicationRouteClients.get(0).getDevice();
|
return mCommunicationRouteClients.get(0);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the device currently requested for communication use case.
|
||||||
|
* Use the device requested by the communication route client selected by
|
||||||
|
* {@link #topCommunicationRouteClient()} if any or none otherwise.
|
||||||
|
* @return AudioDeviceAttributes the requested device for communication.
|
||||||
|
*/
|
||||||
|
@GuardedBy("mDeviceStateLock")
|
||||||
|
private AudioDeviceAttributes requestedCommunicationDevice() {
|
||||||
|
CommunicationRouteClient crc = topCommunicationRouteClient();
|
||||||
|
AudioDeviceAttributes device = crc != null ? crc.getDevice() : null;
|
||||||
if (AudioService.DEBUG_COMM_RTE) {
|
if (AudioService.DEBUG_COMM_RTE) {
|
||||||
Log.v(TAG, "requestedCommunicationDevice, device: "
|
Log.v(TAG, "requestedCommunicationDevice, device: "
|
||||||
+ device + " mode owner pid: " + mModeOwnerPid);
|
+ device + " mode owner pid: " + mModeOwnerPid);
|
||||||
@@ -644,7 +653,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
}
|
}
|
||||||
synchronized (mDeviceStateLock) {
|
synchronized (mDeviceStateLock) {
|
||||||
mBluetoothScoOn = on;
|
mBluetoothScoOn = on;
|
||||||
sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE, SENDMSG_QUEUE, eventSource);
|
postUpdateCommunicationRouteClient(eventSource);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -699,7 +708,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
synchronized (mDeviceStateLock) {
|
synchronized (mDeviceStateLock) {
|
||||||
AudioDeviceAttributes device =
|
AudioDeviceAttributes device =
|
||||||
new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, "");
|
new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, "");
|
||||||
setCommunicationRouteForClient(cb, pid, device, scoAudioMode, eventSource);
|
|
||||||
|
postSetCommunicationRouteForClient(new CommunicationClientInfo(
|
||||||
|
cb, pid, device, scoAudioMode, eventSource));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -717,8 +728,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
if (client == null || !client.requestsBluetoothSco()) {
|
if (client == null || !client.requestsBluetoothSco()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setCommunicationRouteForClient(
|
postSetCommunicationRouteForClient(new CommunicationClientInfo(
|
||||||
cb, pid, null, BtHelper.SCO_MODE_UNDEFINED, eventSource);
|
cb, pid, null, BtHelper.SCO_MODE_UNDEFINED, eventSource));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -960,6 +971,61 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET, SENDMSG_QUEUE, capturePreset);
|
MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET, SENDMSG_QUEUE, capturePreset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*package*/ void postUpdateCommunicationRouteClient(String eventSource) {
|
||||||
|
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 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;
|
||||||
|
|
||||||
|
CommunicationClientInfo(@NonNull IBinder cb, int pid, @NonNull AudioDeviceAttributes device,
|
||||||
|
int scoAudioMode, @NonNull String eventSource) {
|
||||||
|
mCb = cb;
|
||||||
|
mPid = pid;
|
||||||
|
mDevice = device;
|
||||||
|
mScoAudioMode = scoAudioMode;
|
||||||
|
mEventSource = eventSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
// redefine equality op so we can match messages intended for this client
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (o == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(o instanceof CommunicationClientInfo)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mCb.equals(((CommunicationClientInfo) o).mCb)
|
||||||
|
&& mPid == ((CommunicationClientInfo) o).mPid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "CommunicationClientInfo mCb=" + mCb.toString()
|
||||||
|
+"mPid=" + mPid
|
||||||
|
+"mDevice=" + mDevice.toString()
|
||||||
|
+"mScoAudioMode=" + mScoAudioMode
|
||||||
|
+"mEventSource=" + mEventSource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
// Method forwarding between the helper classes (BtHelper, AudioDeviceInventory)
|
// Method forwarding between the helper classes (BtHelper, AudioDeviceInventory)
|
||||||
// only call from a "handle"* method or "on"* method
|
// only call from a "handle"* method or "on"* method
|
||||||
@@ -1270,18 +1336,30 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
synchronized (mDeviceStateLock) {
|
synchronized (mDeviceStateLock) {
|
||||||
mModeOwnerPid = msg.arg1;
|
mModeOwnerPid = msg.arg1;
|
||||||
if (msg.arg2 != AudioSystem.MODE_RINGTONE) {
|
if (msg.arg2 != AudioSystem.MODE_RINGTONE) {
|
||||||
onUpdateCommunicationRoute("setNewModeOwner");
|
onUpdateCommunicationRouteClient("setNewModeOwner");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED:
|
|
||||||
|
case MSG_L_SET_COMMUNICATION_ROUTE_FOR_CLIENT:
|
||||||
synchronized (mSetModeLock) {
|
synchronized (mSetModeLock) {
|
||||||
synchronized (mDeviceStateLock) {
|
synchronized (mDeviceStateLock) {
|
||||||
onCommunicationRouteClientDied((CommunicationRouteClient) msg.obj);
|
CommunicationClientInfo info = (CommunicationClientInfo) msg.obj;
|
||||||
|
setCommunicationRouteForClient(info.mCb, info.mPid, info.mDevice,
|
||||||
|
info.mScoAudioMode, info.mEventSource);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT:
|
||||||
|
synchronized (mSetModeLock) {
|
||||||
|
synchronized (mDeviceStateLock) {
|
||||||
|
onUpdateCommunicationRouteClient((String) msg.obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case MSG_L_UPDATE_COMMUNICATION_ROUTE:
|
case MSG_L_UPDATE_COMMUNICATION_ROUTE:
|
||||||
synchronized (mSetModeLock) {
|
synchronized (mSetModeLock) {
|
||||||
synchronized (mDeviceStateLock) {
|
synchronized (mDeviceStateLock) {
|
||||||
@@ -1289,6 +1367,23 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED:
|
||||||
|
synchronized (mSetModeLock) {
|
||||||
|
synchronized (mDeviceStateLock) {
|
||||||
|
onCommunicationRouteClientDied((CommunicationRouteClient) msg.obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MSG_I_SCO_AUDIO_STATE_CHANGED:
|
||||||
|
synchronized (mSetModeLock) {
|
||||||
|
synchronized (mDeviceStateLock) {
|
||||||
|
mBtHelper.onScoAudioStateChanged(msg.arg1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case MSG_TOGGLE_HDMI:
|
case MSG_TOGGLE_HDMI:
|
||||||
synchronized (mDeviceStateLock) {
|
synchronized (mDeviceStateLock) {
|
||||||
mDeviceInventory.onToggleHdmi();
|
mDeviceInventory.onToggleHdmi();
|
||||||
@@ -1495,6 +1590,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE = 39;
|
private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE = 39;
|
||||||
private static final int MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY = 40;
|
private static final int MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY = 40;
|
||||||
private static final int MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY = 41;
|
private static final int MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY = 41;
|
||||||
|
private static final int MSG_L_SET_COMMUNICATION_ROUTE_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;
|
||||||
|
|
||||||
private static boolean isMessageHandledUnderWakelock(int msgId) {
|
private static boolean isMessageHandledUnderWakelock(int msgId) {
|
||||||
switch(msgId) {
|
switch(msgId) {
|
||||||
@@ -1720,9 +1818,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log.w(TAG, "Communication client died");
|
Log.w(TAG, "Communication client died");
|
||||||
setCommunicationRouteForClient(
|
removeCommunicationRouteClient(client.getBinder(), true);
|
||||||
client.getBinder(), client.getPid(), null, BtHelper.SCO_MODE_UNDEFINED,
|
onUpdateCommunicationRouteClient("onCommunicationRouteClientDied");
|
||||||
"onCommunicationRouteClientDied");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1776,11 +1873,31 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
AudioSystem.setParameters("BT_SCO=on");
|
AudioSystem.setParameters("BT_SCO=on");
|
||||||
}
|
}
|
||||||
if (preferredCommunicationDevice == null) {
|
if (preferredCommunicationDevice == null) {
|
||||||
postRemovePreferredDevicesForStrategy(mCommunicationStrategyId);
|
removePreferredDevicesForStrategySync(mCommunicationStrategyId);
|
||||||
} else {
|
} else {
|
||||||
postSetPreferredDevicesForStrategy(
|
setPreferredDevicesForStrategySync(
|
||||||
mCommunicationStrategyId, Arrays.asList(preferredCommunicationDevice));
|
mCommunicationStrategyId, Arrays.asList(preferredCommunicationDevice));
|
||||||
}
|
}
|
||||||
|
onUpdatePhoneStrategyDevice(preferredCommunicationDevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select new communication device from communication route client at the top of the stack
|
||||||
|
* and restore communication route including restarting SCO audio if needed.
|
||||||
|
*/
|
||||||
|
// @GuardedBy("mSetModeLock")
|
||||||
|
@GuardedBy("mDeviceStateLock")
|
||||||
|
private void onUpdateCommunicationRouteClient(String eventSource) {
|
||||||
|
onUpdateCommunicationRoute(eventSource);
|
||||||
|
CommunicationRouteClient crc = topCommunicationRouteClient();
|
||||||
|
if (AudioService.DEBUG_COMM_RTE) {
|
||||||
|
Log.v(TAG, "onUpdateCommunicationRouteClient, crc: "
|
||||||
|
+ crc + " eventSource: " + eventSource);
|
||||||
|
}
|
||||||
|
if (crc != null) {
|
||||||
|
setCommunicationRouteForClient(crc.getBinder(), crc.getPid(), crc.getDevice(),
|
||||||
|
BtHelper.SCO_MODE_UNDEFINED, eventSource);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onUpdatePhoneStrategyDevice(AudioDeviceAttributes device) {
|
private void onUpdatePhoneStrategyDevice(AudioDeviceAttributes device) {
|
||||||
|
|||||||
@@ -300,11 +300,22 @@ public class BtHelper {
|
|||||||
BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
||||||
setBtScoActiveDevice(btDevice);
|
setBtScoActiveDevice(btDevice);
|
||||||
} else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
|
} else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
|
||||||
boolean broadcast = false;
|
|
||||||
int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
|
|
||||||
int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
|
int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
|
||||||
Log.i(TAG,"receiveBtEvent ACTION_AUDIO_STATE_CHANGED: "+btState);
|
Log.i(TAG,"receiveBtEvent ACTION_AUDIO_STATE_CHANGED: "+btState);
|
||||||
switch (btState) {
|
mDeviceBroker.postScoAudioStateChanged(btState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exclusively called from AudioDeviceBroker when handling MSG_I_SCO_AUDIO_STATE_CHANGED
|
||||||
|
* as part of the serialization of the communication route selection
|
||||||
|
*/
|
||||||
|
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
|
||||||
|
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
|
||||||
|
void onScoAudioStateChanged(int state) {
|
||||||
|
boolean broadcast = false;
|
||||||
|
int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
|
||||||
|
switch (state) {
|
||||||
case BluetoothHeadset.STATE_AUDIO_CONNECTED:
|
case BluetoothHeadset.STATE_AUDIO_CONNECTED:
|
||||||
scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
|
scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
|
||||||
if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL
|
if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL
|
||||||
@@ -325,9 +336,7 @@ public class BtHelper {
|
|||||||
// 2) If audio was connected then disconnected via Bluetooth APIs and
|
// 2) If audio was connected then disconnected via Bluetooth APIs and
|
||||||
// we still have pending activation requests by apps: this is indicated by
|
// we still have pending activation requests by apps: this is indicated by
|
||||||
// state SCO_STATE_ACTIVE_EXTERNAL and BT SCO is requested.
|
// state SCO_STATE_ACTIVE_EXTERNAL and BT SCO is requested.
|
||||||
if (mScoAudioState == SCO_STATE_ACTIVATE_REQ
|
if (mScoAudioState == SCO_STATE_ACTIVATE_REQ) {
|
||||||
|| (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL
|
|
||||||
&& mDeviceBroker.isBluetoothScoRequested())) {
|
|
||||||
if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null
|
if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null
|
||||||
&& connectBluetoothScoAudioHelper(mBluetoothHeadset,
|
&& connectBluetoothScoAudioHelper(mBluetoothHeadset,
|
||||||
mBluetoothHeadsetDevice, mScoAudioMode)) {
|
mBluetoothHeadsetDevice, mScoAudioMode)) {
|
||||||
@@ -359,9 +368,8 @@ public class BtHelper {
|
|||||||
newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
|
newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
|
||||||
sendStickyBroadcastToAll(newIntent);
|
sendStickyBroadcastToAll(newIntent);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return false if SCO isn't connected
|
* @return false if SCO isn't connected
|
||||||
@@ -752,6 +760,15 @@ public class BtHelper {
|
|||||||
case SCO_STATE_ACTIVE_INTERNAL:
|
case SCO_STATE_ACTIVE_INTERNAL:
|
||||||
Log.w(TAG, "requestScoState: already in ACTIVE mode, simply return");
|
Log.w(TAG, "requestScoState: already in ACTIVE mode, simply return");
|
||||||
break;
|
break;
|
||||||
|
case SCO_STATE_ACTIVE_EXTERNAL:
|
||||||
|
/* Confirm SCO Audio connection to requesting app as it is already connected
|
||||||
|
* externally (i.e. through SCO APIs by Telecom service).
|
||||||
|
* Once SCO Audio is disconnected by the external owner, we will reconnect it
|
||||||
|
* automatically on behalf of the requesting app and the state will move to
|
||||||
|
* SCO_STATE_ACTIVE_INTERNAL.
|
||||||
|
*/
|
||||||
|
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
Log.w(TAG, "requestScoState: failed to connect in state "
|
Log.w(TAG, "requestScoState: failed to connect in state "
|
||||||
+ mScoAudioState + ", scoAudioMode=" + scoAudioMode);
|
+ mScoAudioState + ", scoAudioMode=" + scoAudioMode);
|
||||||
|
|||||||
Reference in New Issue
Block a user