Commit 4379c9d5 authored by henrika@chromium.org's avatar henrika@chromium.org

Device enumeration on Android now thread safe.

see https://codereview.chromium.org/78033003/ for the original CL...

BUG=324464
TEST=https://simpl.info/getusermedia/sources/ and manual unittests in media.

Review URL: https://codereview.chromium.org/99063002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@238509 0039d316-1c4b-4281-b951-d872f2087c98
parent b59c161d
......@@ -163,6 +163,9 @@ AudioOutputStream* AudioManagerAndroid::MakeLowLatencyOutputStream(
AudioInputStream* AudioManagerAndroid::MakeLinearInputStream(
const AudioParameters& params, const std::string& device_id) {
// TODO(henrika): add support for device selection if/when any client
// needs it.
DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
return new OpenSLESInputStream(this, params);
}
......
......@@ -19,8 +19,8 @@ import android.os.Build;
import android.os.Process;
import android.util.Log;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
......@@ -114,6 +114,10 @@ class AudioManagerAndroid {
private Integer mAudioDeviceState = STATE_NO_DEVICE_SELECTED;
// Lock to protect |mAudioDevices| which can be accessed from the main
// thread and the audio manager thread.
private final Object mLock = new Object();
// Contains a list of currently available audio devices.
private boolean[] mAudioDevices = new boolean[DEVICE_COUNT];
......@@ -141,9 +145,11 @@ class AudioManagerAndroid {
if (mIsInitialized)
return;
synchronized (mLock) {
for (int i = 0; i < DEVICE_COUNT; ++i) {
mAudioDevices[i] = false;
}
}
// Store microphone mute state and speakerphone state so it can
// be restored when closing.
......@@ -157,10 +163,12 @@ class AudioManagerAndroid {
mAudioDeviceState = STATE_SPEAKERPHONE_ON;
// Initialize audio device list with things we know is always available.
synchronized (mLock) {
if (hasEarpiece()) {
mAudioDevices[DEVICE_EARPIECE] = true;
}
mAudioDevices[DEVICE_SPEAKERPHONE] = true;
}
// Register receiver for broadcasted intents related to adding/
// removing a wired headset (Intent.ACTION_HEADSET_PLUG).
......@@ -213,16 +221,20 @@ class AudioManagerAndroid {
*/
@CalledByNative
public void setDevice(String deviceId) {
boolean devices[] = null;
synchronized (mLock) {
devices = mAudioDevices.clone();
}
if (deviceId.isEmpty()) {
logd("setDevice: default");
// Use a special selection scheme if the default device is selected.
// The "most unique" device will be selected; Bluetooth first, then
// wired headset and last the speaker phone.
if (mAudioDevices[DEVICE_BLUETOOTH_HEADSET]) {
if (devices[DEVICE_BLUETOOTH_HEADSET]) {
// TODO(henrika): possibly need improvements here if we are
// in a STATE_BLUETOOTH_TURNING_OFF state.
setAudioDevice(DEVICE_BLUETOOTH_HEADSET);
} else if (mAudioDevices[DEVICE_WIRED_HEADSET]) {
} else if (devices[DEVICE_WIRED_HEADSET]) {
setAudioDevice(DEVICE_WIRED_HEADSET);
} else {
setAudioDevice(DEVICE_SPEAKERPHONE);
......@@ -248,8 +260,9 @@ class AudioManagerAndroid {
*/
@CalledByNative
public AudioDeviceName[] getAudioInputDeviceNames() {
synchronized (mLock) {
List<String> devices = new ArrayList<String>();
AudioDeviceName[] array = new AudioDeviceName[getNumOfAudioDevices()];
AudioDeviceName[] array = new AudioDeviceName[getNumOfAudioDevicesWithLock()];
int i = 0;
for (int id = 0; id < DEVICE_COUNT; ++id ) {
if (mAudioDevices[id]) {
......@@ -261,6 +274,7 @@ class AudioManagerAndroid {
logd("getAudioInputDeviceNames: " + devices);
return array;
}
}
@CalledByNative
private int getNativeOutputSampleRate() {
......@@ -363,8 +377,7 @@ class AudioManagerAndroid {
* 'state' value where 0 means unplugged, and 1 means plugged.
*/
private void registerForWiredHeadsetIntentBroadcast() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_HEADSET_PLUG);
IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
/**
* Receiver which handles changes in wired headset availablilty.
......@@ -378,23 +391,26 @@ class AudioManagerAndroid {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (!action.equals(Intent.ACTION_HEADSET_PLUG))
if (!action.equals(Intent.ACTION_HEADSET_PLUG)) {
return;
}
int state = intent.getIntExtra("state", STATE_UNPLUGGED);
int microphone = intent.getIntExtra("microphone", HAS_NO_MIC);
String name = intent.getStringExtra("name");
logd("==> onReceive: s=" + state
+ ", m=" + microphone
+ ", n=" + name
+ ", s=" + isInitialStickyBroadcast());
+ ", sb=" + isInitialStickyBroadcast());
switch (state) {
case STATE_UNPLUGGED:
synchronized (mLock) {
// Wired headset and earpiece are mutually exclusive.
mAudioDevices[DEVICE_WIRED_HEADSET] = false;
if (hasEarpiece()) {
mAudioDevices[DEVICE_EARPIECE] = true;
}
}
// If wired headset was used before it was unplugged,
// switch to speaker phone. If it was not in use; just
// log the change.
......@@ -405,10 +421,12 @@ class AudioManagerAndroid {
}
break;
case STATE_PLUGGED:
synchronized (mLock) {
// Wired headset and earpiece are mutually exclusive.
mAudioDevices[DEVICE_WIRED_HEADSET] = true;
mAudioDevices[DEVICE_EARPIECE] = false;
setAudioDevice(DEVICE_WIRED_HEADSET);
}
break;
default:
loge("Invalid state!");
......@@ -472,7 +490,9 @@ class AudioManagerAndroid {
android.bluetooth.BluetoothProfile.STATE_CONNECTED ==
btAdapter.getProfileConnectionState(
android.bluetooth.BluetoothProfile.HEADSET)) {
synchronized (mLock) {
mAudioDevices[DEVICE_BLUETOOTH_HEADSET] = true;
}
// TODO(henrika): ensure that we set the active audio
// device to Bluetooth (not trivial).
setAudioDevice(DEVICE_BLUETOOTH_HEADSET);
......@@ -513,7 +533,7 @@ class AudioManagerAndroid {
reportUpdate();
}
private int getNumOfAudioDevices() {
private int getNumOfAudioDevicesWithLock() {
int count = 0;
for (int i = 0; i < DEVICE_COUNT; ++i) {
if (mAudioDevices[i])
......@@ -524,11 +544,12 @@ class AudioManagerAndroid {
/**
* For now, just log the state change but the idea is that we should
* notifies a registered state change listener (if any) that there has
* notify a registered state change listener (if any) that there has
* been a change in the state.
* TODO(henrika): add support for state change listener.
*/
private void reportUpdate() {
synchronized (mLock) {
List<String> devices = new ArrayList<String>();
for (int i = 0; i < DEVICE_COUNT; ++i) {
if (mAudioDevices[i])
......@@ -537,6 +558,7 @@ class AudioManagerAndroid {
logd("reportUpdate: state=" + mAudioDeviceState
+ ", devices=" + devices);
}
}
private void logDeviceInfo() {
Log.i(TAG, "Manufacturer:" + Build.MANUFACTURER +
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment