Added support for USB audio devices
Two types of USB audio devices are defined:
- USB audio device: the audio device in USB device mode while
the Android device is in USB host mode.
- USB audio accessory: the audio device in USB host mode while
the Android device is in USB device mode.
Renamed intents for analog and digital docks to avoid confusion:
- ACTION_USB_ANLG_HEADSET_PLUG to ACTION_ANALOG_AUDIO_DOCK_PLUG
- ACTION_USB_DGTL_HEADSET_PLUG to ACTION_DIGITAL_AUDIO_DOCK_PLUG
Factorized code in AudioService broadcast receiver.
Change-Id: I1b6d0257a9d68ecb9495c78c98bac8c67fec7891
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 736dd24..18d682d 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2000,8 +2000,8 @@
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_USB_ANLG_HEADSET_PLUG =
- "android.intent.action.USB_ANLG_HEADSET_PLUG";
+ public static final String ACTION_ANALOG_AUDIO_DOCK_PLUG =
+ "android.intent.action.ANALOG_AUDIO_DOCK_PLUG";
/**
* Broadcast Action: A digital audio speaker/headset plugged in or unplugged.
@@ -2015,8 +2015,8 @@
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_USB_DGTL_HEADSET_PLUG =
- "android.intent.action.USB_DGTL_HEADSET_PLUG";
+ public static final String ACTION_DIGITAL_AUDIO_DOCK_PLUG =
+ "android.intent.action.DIGITAL_AUDIO_DOCK_PLUG";
/**
* Broadcast Action: A HMDI cable was plugged or unplugged
@@ -2034,22 +2034,6 @@
"android.intent.action.HDMI_AUDIO_PLUG";
/**
- * Broadcast Action: A USB audio device was plugged in or unplugged.
- *
- * <p>The intent will have the following extra values:
- * <ul>
- * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
- * <li><em>card</em> - ALSA card number (integer) </li>
- * <li><em>device</em> - ALSA device number (integer) </li>
- * </ul>
- * </ul>
- * @hide
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_USB_AUDIO_DEVICE_PLUG =
- "android.intent.action.USB_AUDIO_DEVICE_PLUG";
-
- /**
* Broadcast Action: A USB audio accessory was plugged in or unplugged.
*
* <p>The intent will have the following extra values:
@@ -2066,6 +2050,22 @@
"android.intent.action.USB_AUDIO_ACCESSORY_PLUG";
/**
+ * Broadcast Action: A USB audio device was plugged in or unplugged.
+ *
+ * <p>The intent will have the following extra values:
+ * <ul>
+ * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
+ * <li><em>card</em> - ALSA card number (integer) </li>
+ * <li><em>device</em> - ALSA device number (integer) </li>
+ * </ul>
+ * </ul>
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_USB_AUDIO_DEVICE_PLUG =
+ "android.intent.action.USB_AUDIO_DEVICE_PLUG";
+
+ /**
* <p>Broadcast Action: The user has switched on advanced settings in the settings app:</p>
* <ul>
* <li><em>state</em> - A boolean value indicating whether the settings is on or off.</li>
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index c7e71eb..41d5c32 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -2237,6 +2237,14 @@
* docking station
*/
public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET;
+ /** {@hide} The audio output device code for a USB audio accessory. The accessory is in USB host
+ * mode and the Android device in USB device mode
+ */
+ public static final int DEVICE_OUT_USB_ACCESSORY = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
+ /** {@hide} The audio output device code for a USB audio device. The device is in USB device
+ * mode and the Android device in USB host mode
+ */
+ public static final int DEVICE_OUT_USB_DEVICE = AudioSystem.DEVICE_OUT_USB_DEVICE;
/** {@hide} This is not used as a returned value from {@link #getDevicesForStream}, but could be
* used in the future in a set method to select whatever default device is chosen by the
* platform-specific implementation.
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 2e456f0..48d3712 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -389,9 +389,11 @@
intentFilter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
- intentFilter.addAction(Intent.ACTION_USB_ANLG_HEADSET_PLUG);
- intentFilter.addAction(Intent.ACTION_USB_DGTL_HEADSET_PLUG);
+ intentFilter.addAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG);
+ intentFilter.addAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
intentFilter.addAction(Intent.ACTION_HDMI_AUDIO_PLUG);
+ intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG);
+ intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG);
intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
@@ -2800,6 +2802,28 @@
}
}
+ private boolean handleDeviceConnection(boolean connected, int device, String params) {
+ synchronized (mConnectedDevices) {
+ boolean isConnected = (mConnectedDevices.containsKey(device) &&
+ mConnectedDevices.get(device).equals(params));
+
+ if (isConnected && !connected) {
+ AudioSystem.setDeviceConnectionState(device,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE,
+ params);
+ mConnectedDevices.remove(device);
+ return true;
+ } else if (!isConnected && connected) {
+ AudioSystem.setDeviceConnectionState(device,
+ AudioSystem.DEVICE_STATE_AVAILABLE,
+ params);
+ mConnectedDevices.put(new Integer(device), params);
+ return true;
+ }
+ }
+ return false;
+ }
+
/* cache of the address of the last dock the device was connected to */
private String mDockAddress;
@@ -2810,6 +2834,8 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
+ int device;
+ int state;
if (action.equals(Intent.ACTION_DOCK_EVENT)) {
int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
@@ -2834,15 +2860,15 @@
}
AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
} else if (action.equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) {
- int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
+ state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
BluetoothProfile.STATE_DISCONNECTED);
BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
handleA2dpConnectionStateChange(btDevice, state);
} else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
- int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
+ state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
BluetoothProfile.STATE_DISCONNECTED);
- int device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
+ device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
String address = null;
BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
@@ -2868,129 +2894,56 @@
address = "";
}
- synchronized (mConnectedDevices) {
- boolean isConnected = (mConnectedDevices.containsKey(device) &&
- mConnectedDevices.get(device).equals(address));
-
+ boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
+ if (handleDeviceConnection(connected, device, address)) {
synchronized (mScoClients) {
- if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
- AudioSystem.setDeviceConnectionState(device,
- AudioSystem.DEVICE_STATE_UNAVAILABLE,
- address);
- mConnectedDevices.remove(device);
+ if (connected) {
+ mBluetoothHeadsetDevice = btDevice;
+ } else {
mBluetoothHeadsetDevice = null;
resetBluetoothSco();
- } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
- AudioSystem.setDeviceConnectionState(device,
- AudioSystem.DEVICE_STATE_AVAILABLE,
- address);
- mConnectedDevices.put(new Integer(device), address);
- mBluetoothHeadsetDevice = btDevice;
}
}
}
} else if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
- int state = intent.getIntExtra("state", 0);
+ state = intent.getIntExtra("state", 0);
int microphone = intent.getIntExtra("microphone", 0);
- synchronized (mConnectedDevices) {
- if (microphone != 0) {
- boolean isConnected =
- mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_WIRED_HEADSET);
- if (state == 0 && isConnected) {
- AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET,
- AudioSystem.DEVICE_STATE_UNAVAILABLE,
- "");
- mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADSET);
- } else if (state == 1 && !isConnected) {
- AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET,
- AudioSystem.DEVICE_STATE_AVAILABLE,
- "");
- mConnectedDevices.put(
- new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADSET), "");
- }
- } else {
- boolean isConnected =
- mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
- if (state == 0 && isConnected) {
- AudioSystem.setDeviceConnectionState(
- AudioSystem.DEVICE_OUT_WIRED_HEADPHONE,
- AudioSystem.DEVICE_STATE_UNAVAILABLE,
- "");
- mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
- } else if (state == 1 && !isConnected) {
- AudioSystem.setDeviceConnectionState(
- AudioSystem.DEVICE_OUT_WIRED_HEADPHONE,
- AudioSystem.DEVICE_STATE_AVAILABLE,
- "");
- mConnectedDevices.put(
- new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE), "");
- }
- }
+ if (microphone != 0) {
+ device = AudioSystem.DEVICE_OUT_WIRED_HEADSET;
+ } else {
+ device = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
}
- } else if (action.equals(Intent.ACTION_USB_ANLG_HEADSET_PLUG)) {
- int state = intent.getIntExtra("state", 0);
- Log.v(TAG, "Broadcast Receiver: Got ACTION_USB_ANLG_HEADSET_PLUG, state = "+state);
- synchronized (mConnectedDevices) {
- boolean isConnected =
- mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET);
- if (state == 0 && isConnected) {
- AudioSystem.setDeviceConnectionState(
- AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET,
- AudioSystem.DEVICE_STATE_UNAVAILABLE,
- "");
- mConnectedDevices.remove(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET);
- } else if (state == 1 && !isConnected) {
- AudioSystem.setDeviceConnectionState(
- AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET,
- AudioSystem.DEVICE_STATE_AVAILABLE,
- "");
- mConnectedDevices.put(
- new Integer(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET), "");
- }
- }
+ handleDeviceConnection((state == 1), device, "");
+ } else if (action.equals(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG)) {
+ state = intent.getIntExtra("state", 0);
+ Log.v(TAG, "Broadcast Receiver: Got ACTION_ANALOG_AUDIO_DOCK_PLUG, state = "+state);
+ handleDeviceConnection((state == 1), AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET, "");
} else if (action.equals(Intent.ACTION_HDMI_AUDIO_PLUG)) {
- int state = intent.getIntExtra("state", 0);
+ state = intent.getIntExtra("state", 0);
Log.v(TAG, "Broadcast Receiver: Got ACTION_HDMI_AUDIO_PLUG, state = "+state);
- synchronized (mConnectedDevices) {
- boolean isConnected =
- mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_AUX_DIGITAL);
- if (state == 0 && isConnected) {
- AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_AUX_DIGITAL,
- AudioSystem.DEVICE_STATE_UNAVAILABLE,
- "");
- mConnectedDevices.remove(AudioSystem.DEVICE_OUT_AUX_DIGITAL);
- } else if (state == 1 && !isConnected) {
- AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_AUX_DIGITAL,
- AudioSystem.DEVICE_STATE_AVAILABLE,
- "");
- mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_AUX_DIGITAL), "");
- }
- }
- } else if (action.equals(Intent.ACTION_USB_DGTL_HEADSET_PLUG)) {
- int state = intent.getIntExtra("state", 0);
- Log.v(TAG, "Broadcast Receiver: Got ACTION_USB_DGTL_HEADSET_PLUG, state = "+state);
- synchronized (mConnectedDevices) {
- boolean isConnected =
- mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET);
- if (state == 0 && isConnected) {
- AudioSystem.setDeviceConnectionState(
- AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET,
- AudioSystem.DEVICE_STATE_UNAVAILABLE,
- "");
- mConnectedDevices.remove(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET);
- } else if (state == 1 && !isConnected) {
- AudioSystem.setDeviceConnectionState(
- AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET,
- AudioSystem.DEVICE_STATE_AVAILABLE,
- "");
- mConnectedDevices.put(
- new Integer(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET), "");
- }
- }
+ handleDeviceConnection((state == 1), AudioSystem.DEVICE_OUT_AUX_DIGITAL, "");
+ } else if (action.equals(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG)) {
+ state = intent.getIntExtra("state", 0);
+ Log.v(TAG,
+ "Broadcast Receiver Got ACTION_DIGITAL_AUDIO_DOCK_PLUG, state = " + state);
+ handleDeviceConnection((state == 1), AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET, "");
+ } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ||
+ action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
+ state = intent.getIntExtra("state", 0);
+ int alsaCard = intent.getIntExtra("card", -1);
+ int alsaDevice = intent.getIntExtra("device", -1);
+ String params = "card=" + alsaCard + ";device=" + alsaDevice;
+ device = action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
+ AudioSystem.DEVICE_OUT_USB_ACCESSORY : AudioSystem.DEVICE_OUT_USB_DEVICE;
+ Log.v(TAG, "Broadcast Receiver: Got "
+ + (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
+ "ACTION_USB_AUDIO_ACCESSORY_PLUG" : "ACTION_USB_AUDIO_DEVICE_PLUG")
+ + ", state = " + state + ", card: " + alsaCard + ", device: " + alsaDevice);
+ handleDeviceConnection((state == 1), device, params);
} else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
boolean broadcast = false;
- int state = AudioManager.SCO_AUDIO_STATE_ERROR;
+ int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
synchronized (mScoClients) {
int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
// broadcast intent if the connection was initated by AudioService
@@ -3002,7 +2955,7 @@
}
switch (btState) {
case BluetoothHeadset.STATE_AUDIO_CONNECTED:
- state = AudioManager.SCO_AUDIO_STATE_CONNECTED;
+ scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
@@ -3010,7 +2963,7 @@
}
break;
case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
- state = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
+ scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
mScoAudioState = SCO_STATE_INACTIVE;
clearAllScoClients(0, false);
break;
@@ -3027,11 +2980,11 @@
}
}
if (broadcast) {
- broadcastScoConnectionState(state);
+ broadcastScoConnectionState(scoAudioState);
//FIXME: this is to maintain compatibility with deprecated intent
// AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
- newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
+ newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
mContext.sendStickyBroadcast(newIntent);
}
} else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 18a00bc..9bafa5c 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -202,6 +202,9 @@
public static final int DEVICE_OUT_AUX_DIGITAL = 0x400;
public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800;
public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000;
+ public static final int DEVICE_OUT_USB_ACCESSORY = 0x2000;
+ public static final int DEVICE_OUT_USB_DEVICE = 0x4000;
+
public static final int DEVICE_OUT_DEFAULT = 0x8000;
public static final int DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE |
DEVICE_OUT_SPEAKER |
@@ -216,10 +219,18 @@
DEVICE_OUT_AUX_DIGITAL |
DEVICE_OUT_ANLG_DOCK_HEADSET |
DEVICE_OUT_DGTL_DOCK_HEADSET |
+ DEVICE_OUT_USB_ACCESSORY |
+ DEVICE_OUT_USB_DEVICE |
DEVICE_OUT_DEFAULT);
public static final int DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP |
DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);
+ public static final int DEVICE_OUT_ALL_SCO = (DEVICE_OUT_BLUETOOTH_SCO |
+ DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
+ DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
+ public static final int DEVICE_OUT_ALL_USB = (DEVICE_OUT_USB_ACCESSORY |
+ DEVICE_OUT_USB_DEVICE);
+
// input devices
public static final int DEVICE_IN_COMMUNICATION = 0x10000;
public static final int DEVICE_IN_AMBIENT = 0x20000;
diff --git a/services/java/com/android/server/WiredAccessoryObserver.java b/services/java/com/android/server/WiredAccessoryObserver.java
index 9b4eddc..53d1f0e 100644
--- a/services/java/com/android/server/WiredAccessoryObserver.java
+++ b/services/java/com/android/server/WiredAccessoryObserver.java
@@ -301,13 +301,13 @@
// Pack up the values and broadcast them to everyone
if (headset == BIT_USB_HEADSET_ANLG) {
- intent = new Intent(Intent.ACTION_USB_ANLG_HEADSET_PLUG);
+ intent = new Intent(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
intent.putExtra("state", state);
intent.putExtra("name", headsetName);
ActivityManagerNative.broadcastStickyIntent(intent, null);
} else if (headset == BIT_USB_HEADSET_DGTL) {
- intent = new Intent(Intent.ACTION_USB_DGTL_HEADSET_PLUG);
+ intent = new Intent(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
intent.putExtra("state", state);
intent.putExtra("name", headsetName);