diff options
author | henrika@chromium.org <henrika@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-29 20:00:00 +0000 |
---|---|---|
committer | henrika@chromium.org <henrika@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-29 20:00:00 +0000 |
commit | 5ff853ecbdc86dcb25249d84d87d0afeb7caad43 (patch) | |
tree | 7b7899906a8e725c0b283773296062c2171120d5 /media | |
parent | 9b8da4a39ad6c94b2f464c418bf844cc3ede0d6d (diff) | |
download | chromium_src-5ff853ecbdc86dcb25249d84d87d0afeb7caad43.zip chromium_src-5ff853ecbdc86dcb25249d84d87d0afeb7caad43.tar.gz chromium_src-5ff853ecbdc86dcb25249d84d87d0afeb7caad43.tar.bz2 |
Adding device enumeration to the Android device manager.
Main goal is to support the getSources API (see TEST) and to allow VoIP clients in Chrome to use Bluetooth headsets.
BUG=324464
TEST=https://simpl.info/getusermedia/sources/ and manual unittests in media.
Review URL: https://codereview.chromium.org/78033003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@237942 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/audio/android/audio_manager_android.cc | 71 | ||||
-rw-r--r-- | media/audio/android/audio_manager_android.h | 5 | ||||
-rw-r--r-- | media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java | 476 |
3 files changed, 496 insertions, 56 deletions
diff --git a/media/audio/android/audio_manager_android.cc b/media/audio/android/audio_manager_android.cc index dc77a4c..3466510 100644 --- a/media/audio/android/audio_manager_android.cc +++ b/media/audio/android/audio_manager_android.cc @@ -4,7 +4,12 @@ #include "media/audio/android/audio_manager_android.h" +#include "base/android/build_info.h" +#include "base/android/jni_array.h" +#include "base/android/jni_string.h" +#include "base/android/scoped_java_ref.h" #include "base/logging.h" +#include "base/strings/string_number_conversions.h" #include "jni/AudioManagerAndroid_jni.h" #include "media/audio/android/opensles_input.h" #include "media/audio/android/opensles_output.h" @@ -13,6 +18,12 @@ #include "media/audio/fake_audio_input_stream.h" #include "media/base/channel_layout.h" +using base::android::AppendJavaStringArrayToStringVector; +using base::android::AttachCurrentThread; +using base::android::ConvertJavaStringToUTF8; +using base::android::ConvertUTF8ToJavaString; +using base::android::ScopedJavaLocalRef; + namespace media { static void AddDefaultDevice(AudioDeviceNames* device_names) { @@ -42,9 +53,11 @@ AudioManagerAndroid::AudioManagerAndroid() { Java_AudioManagerAndroid_createAudioManagerAndroid( base::android::AttachCurrentThread(), base::android::GetApplicationContext())); + Init(); } AudioManagerAndroid::~AudioManagerAndroid() { + Close(); Shutdown(); } @@ -58,11 +71,31 @@ bool AudioManagerAndroid::HasAudioInputDevices() { void AudioManagerAndroid::GetAudioInputDeviceNames( AudioDeviceNames* device_names) { + // Always add default device parameters as first element. AddDefaultDevice(device_names); + + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobjectArray> j_device_array = + Java_AudioManagerAndroid_getAudioInputDeviceNames( + env, j_audio_manager_.obj()); + jsize len = env->GetArrayLength(j_device_array.obj()); + AudioDeviceName device; + for (jsize i = 0; i < len; ++i) { + ScopedJavaLocalRef<jobject> j_device( + env, env->GetObjectArrayElement(j_device_array.obj(), i)); + ScopedJavaLocalRef<jstring> j_device_name = + Java_AudioDeviceName_name(env, j_device.obj()); + ConvertJavaStringToUTF8(env, j_device_name.obj(), &device.device_name); + ScopedJavaLocalRef<jstring> j_device_id = + Java_AudioDeviceName_id(env, j_device.obj()); + ConvertJavaStringToUTF8(env, j_device_id.obj(), &device.unique_id); + device_names->push_back(device); + } } void AudioManagerAndroid::GetAudioOutputDeviceNames( AudioDeviceNames* device_names) { + // TODO(henrika): enumerate using GetAudioInputDeviceNames(). AddDefaultDevice(device_names); } @@ -91,7 +124,6 @@ AudioOutputStream* AudioManagerAndroid::MakeAudioOutputStream( std::string()); if (stream && output_stream_count() == 1) { SetAudioMode(kAudioModeInCommunication); - RegisterHeadsetReceiver(); } return stream; } @@ -106,7 +138,6 @@ AudioInputStream* AudioManagerAndroid::MakeAudioInputStream( void AudioManagerAndroid::ReleaseOutputStream(AudioOutputStream* stream) { AudioManagerBase::ReleaseOutputStream(stream); if (!output_stream_count()) { - UnregisterHeadsetReceiver(); SetAudioMode(kAudioModeNormal); } } @@ -139,6 +170,12 @@ AudioInputStream* AudioManagerAndroid::MakeLinearInputStream( AudioInputStream* AudioManagerAndroid::MakeLowLatencyInputStream( const AudioParameters& params, const std::string& device_id) { DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); + DLOG_IF(ERROR, device_id.empty()) << "Invalid device ID!"; + // Utilize the device ID to select the correct input device. + // Note that the input device is always associated with a certain output + // device, i.e., this selection does also switch the output device. + // All input and output streams will be affected by the device selection. + SetAudioDevice(device_id); return new OpenSLESInputStream(this, params); } @@ -188,22 +225,36 @@ bool AudioManagerAndroid::RegisterAudioManager(JNIEnv* env) { return RegisterNativesImpl(env); } -void AudioManagerAndroid::SetAudioMode(int mode) { - Java_AudioManagerAndroid_setMode( +void AudioManagerAndroid::Init() { + Java_AudioManagerAndroid_init( base::android::AttachCurrentThread(), - j_audio_manager_.obj(), mode); + j_audio_manager_.obj()); } -void AudioManagerAndroid::RegisterHeadsetReceiver() { - Java_AudioManagerAndroid_registerHeadsetReceiver( +void AudioManagerAndroid::Close() { + Java_AudioManagerAndroid_close( base::android::AttachCurrentThread(), j_audio_manager_.obj()); } -void AudioManagerAndroid::UnregisterHeadsetReceiver() { - Java_AudioManagerAndroid_unregisterHeadsetReceiver( +void AudioManagerAndroid::SetAudioMode(int mode) { + Java_AudioManagerAndroid_setMode( base::android::AttachCurrentThread(), - j_audio_manager_.obj()); + j_audio_manager_.obj(), mode); +} + +void AudioManagerAndroid::SetAudioDevice(const std::string& device_id) { + JNIEnv* env = AttachCurrentThread(); + + // Send the unique device ID to the Java audio manager and make the + // device switch. Provide an empty string to the Java audio manager + // if the default device is selected. + ScopedJavaLocalRef<jstring> j_device_id = ConvertUTF8ToJavaString( + env, + device_id == AudioManagerBase::kDefaultDeviceId ? + std::string() : device_id); + Java_AudioManagerAndroid_setDevice( + env, j_audio_manager_.obj(), j_device_id.obj()); } int AudioManagerAndroid::GetNativeOutputSampleRate() { diff --git a/media/audio/android/audio_manager_android.h b/media/audio/android/audio_manager_android.h index ed2b2c3..cb90416 100644 --- a/media/audio/android/audio_manager_android.h +++ b/media/audio/android/audio_manager_android.h @@ -60,9 +60,10 @@ class MEDIA_EXPORT AudioManagerAndroid : public AudioManagerBase { const AudioParameters& input_params) OVERRIDE; private: + void Init(); + void Close(); void SetAudioMode(int mode); - void RegisterHeadsetReceiver(); - void UnregisterHeadsetReceiver(); + void SetAudioDevice(const std::string& device_id); int GetNativeOutputSampleRate(); bool IsAudioLowLatencySupported(); int GetAudioLowLatencyOutputFrameSize(); diff --git a/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java b/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java index 0f0cfb6..db674f5 100644 --- a/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java +++ b/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java @@ -4,6 +4,8 @@ package org.chromium.media; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -14,8 +16,15 @@ import android.media.AudioManager; import android.media.AudioRecord; import android.media.AudioTrack; import android.os.Build; +import android.os.Process; import android.util.Log; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + import org.chromium.base.CalledByNative; import org.chromium.base.JNINamespace; @@ -23,30 +32,95 @@ import org.chromium.base.JNINamespace; class AudioManagerAndroid { private static final String TAG = "AudioManagerAndroid"; - // Most of Google lead devices use 44.1K as the default sampling rate, 44.1K - // is also widely used on other android devices. + // Set to true to enable debug logs. Always check in as false. + private static final boolean DEBUG = false; + + /** Simple container for device information. */ + private static class AudioDeviceName { + private final int mId; + private final String mName; + + private AudioDeviceName(int id, String name) { + mId = id; + mName = name; + } + + @CalledByNative("AudioDeviceName") + private String id() { return String.valueOf(mId); } + + @CalledByNative("AudioDeviceName") + private String name() { return mName; } + } + + // Supported audio device types. + private static final int DEVICE_INVALID = -1; + private static final int DEVICE_SPEAKERPHONE = 0; + private static final int DEVICE_WIRED_HEADSET = 1; + private static final int DEVICE_EARPIECE = 2; + private static final int DEVICE_BLUETOOTH_HEADSET = 3; + private static final int DEVICE_COUNT = 4; + + // Maps audio device types to string values. This map must be in sync + // with the device types above. + // TODO(henrika): add support for proper detection of device names and + // localize the name strings by using resource strings. + private static final String[] DEVICE_NAMES = new String[] { + "Speakerphone", + "Wired headset", // With or without microphone + "Headset earpiece", // Only available on mobile phones + "Bluetooth headset", + }; + + // List of valid device types. + private static Integer[] VALID_DEVICES = new Integer[] { + DEVICE_SPEAKERPHONE, + DEVICE_WIRED_HEADSET, + DEVICE_EARPIECE, + DEVICE_BLUETOOTH_HEADSET, + }; + + // The device does not have any audio device. + static final int STATE_NO_DEVICE_SELECTED = 0; + // The speakerphone is on and an associated microphone is used. + static final int STATE_SPEAKERPHONE_ON = 1; + // The phone's earpiece is on and an associated microphone is used. + static final int STATE_EARPIECE_ON = 2; + // A wired headset (with or without a microphone) is plugged in. + static final int STATE_WIRED_HEADSET_ON = 3; + // The audio stream is being directed to a Bluetooth headset. + static final int STATE_BLUETOOTH_ON = 4; + // We've requested that the audio stream be directed to Bluetooth, but + // have not yet received a response from the framework. + static final int STATE_BLUETOOTH_TURNING_ON = 5; + // We've requested that the audio stream stop being directed to + // Bluetooth, but have not yet received a response from the framework. + static final int STATE_BLUETOOTH_TURNING_OFF = 6; + // TODO(henrika): document the valid state transitions. + + // Use 44.1kHz as the default sampling rate. private static final int DEFAULT_SAMPLING_RATE = 44100; // Randomly picked up frame size which is close to return value on N4. - // Return this default value when - // getProperty(PROPERTY_OUTPUT_FRAMES_PER_BUFFER) fails. + // Return this value when getProperty(PROPERTY_OUTPUT_FRAMES_PER_BUFFER) + // fails. private static final int DEFAULT_FRAME_PER_BUFFER = 256; private final AudioManager mAudioManager; private final Context mContext; - private BroadcastReceiver mReceiver; - private boolean mOriginalSpeakerStatus; + private boolean mHasBluetoothPermission = false; + private boolean mIsInitialized = false; + private boolean mSavedIsSpeakerphoneOn; + private boolean mSavedIsMicrophoneMute; - @CalledByNative - public void setMode(int mode) { - try { - mAudioManager.setMode(mode); - } catch (SecurityException e) { - Log.e(TAG, "setMode exception: " + e.getMessage()); - logDeviceInfo(); - } - } + private Integer mAudioDeviceState = STATE_NO_DEVICE_SELECTED; + + // Contains a list of currently available audio devices. + private boolean[] mAudioDevices = new boolean[DEVICE_COUNT]; + // Broadcast receiver for wired headset intent broadcasts. + private BroadcastReceiver mWiredHeadsetReceiver; + + /** Construction */ @CalledByNative private static AudioManagerAndroid createAudioManagerAndroid(Context context) { return new AudioManagerAndroid(context); @@ -57,46 +131,135 @@ class AudioManagerAndroid { mAudioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE); } + /** + * Saves the initial speakerphone and microphone state. + * Populates the list of available audio devices and registers receivers + * for broadcasted intents related to wired headset and bluetooth devices. + */ @CalledByNative - public void registerHeadsetReceiver() { - if (mReceiver != null) { + public void init() { + if (mIsInitialized) return; + + for (int i = 0; i < DEVICE_COUNT; ++i) { + mAudioDevices[i] = false; } - mOriginalSpeakerStatus = mAudioManager.isSpeakerphoneOn(); - if (!mOriginalSpeakerStatus) { - mAudioManager.setSpeakerphoneOn(true); + // Store microphone mute state and speakerphone state so it can + // be restored when closing. + mSavedIsSpeakerphoneOn = mAudioManager.isSpeakerphoneOn(); + mSavedIsMicrophoneMute = mAudioManager.isMicrophoneMute(); + + // Always enable speaker phone by default. This state might be reset + // by the wired headset receiver when it gets its initial sticky + // intent, if any. + setSpeakerphoneOn(true); + mAudioDeviceState = STATE_SPEAKERPHONE_ON; + + // Initialize audio device list with things we know is always available. + if (hasEarpiece()) { + mAudioDevices[DEVICE_EARPIECE] = true; } - IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG); + mAudioDevices[DEVICE_SPEAKERPHONE] = true; - mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (Intent.ACTION_HEADSET_PLUG.equals(intent.getAction())) { - try { - mAudioManager.setSpeakerphoneOn( - intent.getIntExtra("state", 0) == 0); - } catch (SecurityException e) { - Log.e(TAG, "setMode exception: " + e.getMessage()); - logDeviceInfo(); - } - } - } - }; - mContext.registerReceiver(mReceiver, filter); + // Register receiver for broadcasted intents related to adding/ + // removing a wired headset (Intent.ACTION_HEADSET_PLUG). + // Also starts routing to the wired headset/headphone if one is + // already attached (can be overridden by a Bluetooth headset). + registerForWiredHeadsetIntentBroadcast(); + + // Start routing to Bluetooth if there's a connected device. + // TODO(henrika): the actual routing part is not implemented yet. + // All we do currently is to detect if BT headset is attached or not. + initBluetooth(); + + mIsInitialized = true; } + /** + * Unregister all previously registered intent receivers and restore + * the stored state (stored in {@link #init()}). + */ @CalledByNative - public void unregisterHeadsetReceiver() { - mContext.unregisterReceiver(mReceiver); - mReceiver = null; - mAudioManager.setSpeakerphoneOn(mOriginalSpeakerStatus); + public void close() { + if (!mIsInitialized) + return; + + unregisterForWiredHeadsetIntentBroadcast(); + + // Restore previously stored audio states. + setMicrophoneMute(mSavedIsMicrophoneMute); + setSpeakerphoneOn(mSavedIsSpeakerphoneOn); + + mIsInitialized = false; } - private void logDeviceInfo() { - Log.i(TAG, "Manufacturer:" + Build.MANUFACTURER + - " Board: " + Build.BOARD + " Device: " + Build.DEVICE + - " Model: " + Build.MODEL + " PRODUCT: " + Build.PRODUCT); + @CalledByNative + public void setMode(int mode) { + try { + mAudioManager.setMode(mode); + } catch (SecurityException e) { + Log.e(TAG, "setMode exception: " + e.getMessage()); + logDeviceInfo(); + } + } + + /** + * Activates, i.e., starts routing audio to, the specified audio device. + * + * @param deviceId Unique device ID (integer converted to string) + * representing the selected device. This string is empty if the so-called + * default device is selected. + */ + @CalledByNative + public void setDevice(String deviceId) { + 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]) { + // 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]) { + setAudioDevice(DEVICE_WIRED_HEADSET); + } else { + setAudioDevice(DEVICE_SPEAKERPHONE); + } + } else { + logd("setDevice: " + deviceId); + // A non-default device is specified. Verify that it is valid + // device, and if so, start using it. + List<Integer> validIds = Arrays.asList(VALID_DEVICES); + Integer id = Integer.valueOf(deviceId); + if (validIds.contains(id)) { + setAudioDevice(id.intValue()); + } else { + loge("Invalid device ID!"); + } + } + } + + /** + * @return the current list of available audio devices. + * Note that this call does not trigger any update of the list of devices, + * it only copies the current state in to the output array. + */ + @CalledByNative + public AudioDeviceName[] getAudioInputDeviceNames() { + List<String> devices = new ArrayList<String>(); + AudioDeviceName[] array = new AudioDeviceName[getNumOfAudioDevices()]; + int i = 0; + for (int id = 0; id < DEVICE_COUNT; ++id ) { + if (mAudioDevices[id]) { + array[i] = new AudioDeviceName(id, DEVICE_NAMES[id]); + devices.add(DEVICE_NAMES[id]); + i++; + } + } + logd("getAudioInputDeviceNames: " + devices); + return array; } @CalledByNative @@ -165,4 +328,229 @@ class AudioManagerAndroid { DEFAULT_FRAME_PER_BUFFER : Integer.parseInt(framesPerBuffer)); } + /** Sets the speaker phone mode. */ + public void setSpeakerphoneOn(boolean on) { + boolean wasOn = mAudioManager.isSpeakerphoneOn(); + if (wasOn == on) { + return; + } + mAudioManager.setSpeakerphoneOn(on); + } + + /** Sets the microphone mute state. */ + public void setMicrophoneMute(boolean on) { + boolean wasMuted = mAudioManager.isMicrophoneMute(); + if (wasMuted == on) { + return; + } + mAudioManager.setMicrophoneMute(on); + } + + /** Gets the current microphone mute state. */ + public boolean isMicrophoneMute() { + return mAudioManager.isMicrophoneMute(); + } + + /** Gets the current earpice state. */ + private boolean hasEarpiece() { + return mContext.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_TELEPHONY); + } + + /** + * Registers receiver for the broadcasted intent when a wired headset is + * plugged in or unplugged. The received intent will have an extra + * 'state' value where 0 means unplugged, and 1 means plugged. + */ + private void registerForWiredHeadsetIntentBroadcast() { + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_HEADSET_PLUG); + + /** + * Receiver which handles changes in wired headset availablilty. + */ + mWiredHeadsetReceiver = new BroadcastReceiver() { + private static final int STATE_UNPLUGGED = 0; + private static final int STATE_PLUGGED = 1; + private static final int HAS_NO_MIC = 0; + private static final int HAS_MIC = 1; + + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + 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()); + + switch (state) { + case STATE_UNPLUGGED: + // 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. + if (mAudioDeviceState == STATE_WIRED_HEADSET_ON) { + setAudioDevice(DEVICE_SPEAKERPHONE); + } else { + reportUpdate(); + } + break; + case STATE_PLUGGED: + // 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!"); + break; + } + } + }; + + // Note: the intent we register for here is sticky, so it'll tell us + // immediately what the last action was (plugged or unplugged). + // It will enable us to set the speakerphone correctly. + mContext.registerReceiver(mWiredHeadsetReceiver, filter); + } + + /** Unregister receiver for broadcasted ACTION_HEADSET_PLUG intent. */ + private void unregisterForWiredHeadsetIntentBroadcast() { + mContext.unregisterReceiver(mWiredHeadsetReceiver); + mWiredHeadsetReceiver = null; + } + + /** + * Check if Bluetooth device is connected, register Bluetooth receiver + * and start routing to Bluetooth if a device is connected. + * TODO(henrika): currently only supports the detecion part at startup. + */ + private void initBluetooth() { + // Bail out if we don't have the required permission. + mHasBluetoothPermission = mContext.checkPermission( + android.Manifest.permission.BLUETOOTH, + Process.myPid(), + Process.myUid()) == PackageManager.PERMISSION_GRANTED; + if (!mHasBluetoothPermission) { + loge("BLUETOOTH permission is missing!"); + return; + } + + // To get a BluetoothAdapter representing the local Bluetooth adapter, + // when running on JELLY_BEAN_MR1 (4.2) and below, call the static + // getDefaultAdapter() method; when running on JELLY_BEAN_MR2 (4.3) and + // higher, retrieve it through getSystemService(String) with + // BLUETOOTH_SERVICE. + // Note: Most methods require the BLUETOOTH permission. + BluetoothAdapter btAdapter = null; + if (android.os.Build.VERSION.SDK_INT <= + android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { + // Use static method for Android 4.2 and below to get the + // BluetoothAdapter. + btAdapter = BluetoothAdapter.getDefaultAdapter(); + } else { + // Use BluetoothManager to get the BluetoothAdapter for + // Android 4.3 and above. + BluetoothManager btManager = + (BluetoothManager)mContext.getSystemService( + Context.BLUETOOTH_SERVICE); + btAdapter = btManager.getAdapter(); + } + + if (btAdapter != null && + // android.bluetooth.BluetoothAdapter.getProfileConnectionState + // requires BLUETOOTH permission. + android.bluetooth.BluetoothProfile.STATE_CONNECTED == + btAdapter.getProfileConnectionState( + android.bluetooth.BluetoothProfile.HEADSET)) { + mAudioDevices[DEVICE_BLUETOOTH_HEADSET] = true; + // TODO(henrika): ensure that we set the active audio + // device to Bluetooth (not trivial). + setAudioDevice(DEVICE_BLUETOOTH_HEADSET); + } + } + + /** + * Changes selection of the currently active audio device. + * + * @param device Specifies the selected audio device. + */ + public void setAudioDevice(int device) { + switch (device) { + case DEVICE_BLUETOOTH_HEADSET: + // TODO(henrika): add support for turning on an routing to + // BT here. + if (DEBUG) logd("--- TO BE IMPLEMENTED ---"); + break; + case DEVICE_SPEAKERPHONE: + // TODO(henrika): turn off BT if required. + mAudioDeviceState = STATE_SPEAKERPHONE_ON; + setSpeakerphoneOn(true); + break; + case DEVICE_WIRED_HEADSET: + // TODO(henrika): turn off BT if required. + mAudioDeviceState = STATE_WIRED_HEADSET_ON; + setSpeakerphoneOn(false); + break; + case DEVICE_EARPIECE: + // TODO(henrika): turn off BT if required. + mAudioDeviceState = STATE_EARPIECE_ON; + setSpeakerphoneOn(false); + break; + default: + loge("Invalid audio device selection!"); + break; + } + reportUpdate(); + } + + private int getNumOfAudioDevices() { + int count = 0; + for (int i = 0; i < DEVICE_COUNT; ++i) { + if (mAudioDevices[i]) + count++; + } + return count; + } + + /** + * 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 + * been a change in the state. + * TODO(henrika): add support for state change listener. + */ + private void reportUpdate() { + List<String> devices = new ArrayList<String>(); + for (int i = 0; i < DEVICE_COUNT; ++i) { + if (mAudioDevices[i]) + devices.add(DEVICE_NAMES[i]); + } + logd("reportUpdate: state=" + mAudioDeviceState + + ", devices=" + devices); + } + + private void logDeviceInfo() { + Log.i(TAG, "Manufacturer:" + Build.MANUFACTURER + + " Board: " + Build.BOARD + " Device: " + Build.DEVICE + + " Model: " + Build.MODEL + " PRODUCT: " + Build.PRODUCT); + } + + /** Trivial helper method for debug logging */ + private void logd(String msg) { + Log.d(TAG, msg); + } + + /** Trivial helper method for error logging */ + private void loge(String msg) { + Log.e(TAG, msg); + } } |