Fix issue 1795088       Improve audio routing code

Initial commit for review.
Integrated comments after patch set 1 review.
Fixed lockup in AudioFlinger::ThreadBase::exit()
Fixed lockup when playing tone with AudioPlocyService startTone()
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index 722a7cc..fb436e5 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -54,7 +54,6 @@
     private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
     private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
 
-    private static final String A2DP_SINK_ADDRESS = "a2dp_sink_address";
     private static final String BLUETOOTH_ENABLED = "bluetooth_enabled";
 
     private static final int MESSAGE_CONNECT_TO = 1;
@@ -238,7 +237,7 @@
                     }
             }
         }
-        mAudioManager.setParameter(BLUETOOTH_ENABLED, "true");
+        mAudioManager.setParameters(BLUETOOTH_ENABLED+"=true");
     }
 
     private synchronized void onBluetoothDisable() {
@@ -262,8 +261,8 @@
             }
             mAudioDevices.clear();
         }
-        mAudioManager.setBluetoothA2dpOn(false);
-        mAudioManager.setParameter(BLUETOOTH_ENABLED, "false");
+
+        mAudioManager.setParameters(BLUETOOTH_ENABLED+"=false");
     }
 
     public synchronized int connectSink(String address) {
@@ -403,8 +402,7 @@
                    Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
                    mContext.sendBroadcast(intent);
                 }
-                if (--mSinkCount == 0)
-                    mAudioManager.setBluetoothA2dpOn(false);
+                mSinkCount--;
             } else if (state == BluetoothA2dp.STATE_CONNECTED) {
                 mSinkCount ++;
             }
@@ -417,11 +415,6 @@
             mContext.sendBroadcast(intent, BLUETOOTH_PERM);
 
             if (DBG) log("A2DP state : address: " + address + " State:" + prevState + "->" + state);
-
-            if (state == BluetoothA2dp.STATE_CONNECTED) {
-                mAudioManager.setParameter(A2DP_SINK_ADDRESS, address);
-                mAudioManager.setBluetoothA2dpOn(true);
-            }
         }
     }
 
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 44a9e8c..0be996d 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -28,8 +28,8 @@
 #include "android_runtime/AndroidRuntime.h"
 
 #include "utils/Log.h"
-#include "media/AudioSystem.h"
 #include "media/AudioRecord.h"
+#include "media/mediarecorder.h"
 
 
 // ----------------------------------------------------------------------------
@@ -62,7 +62,7 @@
 #define AUDIORECORD_ERROR_BAD_VALUE                 -2
 #define AUDIORECORD_ERROR_INVALID_OPERATION         -3
 #define AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT      -16
-#define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELCOUNT -17
+#define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK -17
 #define AUDIORECORD_ERROR_SETUP_INVALIDFORMAT       -18
 #define AUDIORECORD_ERROR_SETUP_INVALIDSOURCE       -19
 #define AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED    -20
@@ -122,17 +122,18 @@
 // ----------------------------------------------------------------------------
 static int
 android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
-        jint source, jint sampleRateInHertz, jint nbChannels, 
+        jint source, jint sampleRateInHertz, jint channels,
         jint audioFormat, jint buffSizeInBytes)
 {
     //LOGV(">> Entering android_media_AudioRecord_setup");
-    //LOGV("sampleRate=%d, audioFormat=%d, nbChannels=%d, buffSizeInBytes=%d",
-    //     sampleRateInHertz, audioFormat, nbChannels,     buffSizeInBytes);
+    //LOGV("sampleRate=%d, audioFormat=%d, channels=%x, buffSizeInBytes=%d",
+    //     sampleRateInHertz, audioFormat, channels,     buffSizeInBytes);
 
-    if ((nbChannels == 0) || (nbChannels > 2)) {
+    if (!AudioSystem::isInputChannel(channels)) {
         LOGE("Error creating AudioRecord: channel count is not 1 or 2.");
-        return AUDIORECORD_ERROR_SETUP_INVALIDCHANNELCOUNT;
+        return AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK;
     }
+    uint32_t nbChannels = AudioSystem::popCount(channels);
 
     // compare the format against the Java constants
     if ((audioFormat != javaAudioRecordFields.PCM16) 
@@ -152,12 +153,7 @@
     int frameSize = nbChannels * bytesPerSample;
     size_t frameCount = buffSizeInBytes / frameSize;
     
-    // convert and check input source value
-    // input_source values defined in AudioRecord.h are equal to
-    // JAVA MediaRecord.AudioSource values minus 1.
-    AudioRecord::input_source arSource = (AudioRecord::input_source)(source - 1);
-    if (arSource < AudioRecord::DEFAULT_INPUT ||
-        arSource >= AudioRecord::NUM_INPUT_SOURCES) {
+    if (source >= AUDIO_SOURCE_LIST_END) {
         LOGE("Error creating AudioRecord: unknown source.");
         return AUDIORECORD_ERROR_SETUP_INVALIDSOURCE;
     }
@@ -184,10 +180,10 @@
     // we use a weak reference so the AudioRecord object can be garbage collected.
     lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
     
-    lpRecorder->set(arSource,
+    lpRecorder->set(source,
         sampleRateInHertz,
         format,        // word length, PCM
-        nbChannels,
+        channels,
         frameCount,
         0,             // flags
         recorderCallback,// callback_t
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 692610e..3d8d296 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -50,25 +50,6 @@
 }
 
 static int
-android_media_AudioSystem_setVolume(JNIEnv *env, jobject clazz, jint type, jint volume)
-{
-    LOGV("setVolume(%d)", int(volume));
-    
-    return check_AudioSystem_Command(AudioSystem::setStreamVolume(type, AudioSystem::linearToLog(volume)));
-}
-
-static int
-android_media_AudioSystem_getVolume(JNIEnv *env, jobject clazz, jint type)
-{
-    float v;
-    int v_int = -1;
-    if (AudioSystem::getStreamVolume(int(type), &v) == NO_ERROR) {
-        v_int = AudioSystem::logToLinear(v);
-    }
-    return v_int;
-}
-
-static int
 android_media_AudioSystem_muteMicrophone(JNIEnv *env, jobject thiz, jboolean on)
 {
     return check_AudioSystem_Command(AudioSystem::muteMicrophone(on));
@@ -82,34 +63,6 @@
     return state;
 }
 
-static int
-android_media_AudioSystem_setRouting(JNIEnv *env, jobject clazz, jint mode, jint routes, jint mask)
-{
-    return check_AudioSystem_Command(AudioSystem::setRouting(mode, uint32_t(routes), uint32_t(mask)));
-}
-
-static jint
-android_media_AudioSystem_getRouting(JNIEnv *env, jobject clazz, jint mode)
-{
-    uint32_t routes = -1;
-    AudioSystem::getRouting(mode, &routes);
-    return jint(routes);
-}
-
-static int
-android_media_AudioSystem_setMode(JNIEnv *env, jobject clazz, jint mode)
-{
-    return check_AudioSystem_Command(AudioSystem::setMode(mode));
-}
-
-static jint
-android_media_AudioSystem_getMode(JNIEnv *env, jobject clazz)
-{
-    int mode = AudioSystem::MODE_INVALID;
-    AudioSystem::getMode(&mode);
-    return jint(mode);
-}
-
 static jboolean
 android_media_AudioSystem_isMusicActive(JNIEnv *env, jobject thiz)
 {
@@ -118,16 +71,29 @@
     return state;
 }
 
-// Temporary interface, do not use
-// TODO: Replace with a more generic key:value get/set mechanism
-static void
-android_media_AudioSystem_setParameter(JNIEnv *env, jobject thiz, jstring key, jstring value)
+static int
+android_media_AudioSystem_setParameters(JNIEnv *env, jobject thiz, jstring keyValuePairs)
 {
-    const char *c_key = env->GetStringUTFChars(key, NULL);
-    const char *c_value = env->GetStringUTFChars(value, NULL);
-    AudioSystem::setParameter(c_key, c_value);
-    env->ReleaseStringUTFChars(key, c_key);
-    env->ReleaseStringUTFChars(value, c_value);
+    const jchar* c_keyValuePairs = env->GetStringCritical(keyValuePairs, 0);
+    String8 c_keyValuePairs8;
+    if (keyValuePairs) {
+        c_keyValuePairs8 = String8(c_keyValuePairs, env->GetStringLength(keyValuePairs));
+        env->ReleaseStringCritical(keyValuePairs, c_keyValuePairs);
+    }
+    int status = check_AudioSystem_Command(AudioSystem::setParameters(0, c_keyValuePairs8));
+    return status;
+}
+
+static jstring
+android_media_AudioSystem_getParameters(JNIEnv *env, jobject thiz, jstring keys)
+{
+    const jchar* c_keys = env->GetStringCritical(keys, 0);
+    String8 c_keys8;
+    if (keys) {
+        c_keys8 = String8(c_keys, env->GetStringLength(keys));
+        env->ReleaseStringCritical(keys, c_keys);
+    }
+    return env->NewStringUTF(AudioSystem::getParameters(0, c_keys8).string());
 }
 
 void android_media_AudioSystem_error_callback(status_t err)
@@ -152,19 +118,93 @@
     env->CallStaticVoidMethod(clazz, env->GetStaticMethodID(clazz, "errorCallbackFromNative","(I)V"), error);
 }
 
+static int
+android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address)
+{
+    const char *c_address = env->GetStringUTFChars(device_address, NULL);
+    int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast <AudioSystem::audio_devices>(device),
+                                          static_cast <AudioSystem::device_connection_state>(state),
+                                          c_address));
+    env->ReleaseStringUTFChars(device_address, c_address);
+    return status;
+}
+
+static int
+android_media_AudioSystem_getDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jstring device_address)
+{
+    const char *c_address = env->GetStringUTFChars(device_address, NULL);
+    int state = static_cast <int>(AudioSystem::getDeviceConnectionState(static_cast <AudioSystem::audio_devices>(device),
+                                          c_address));
+    env->ReleaseStringUTFChars(device_address, c_address);
+    return state;
+}
+
+static int
+android_media_AudioSystem_setPhoneState(JNIEnv *env, jobject thiz, jint state)
+{
+    return check_AudioSystem_Command(AudioSystem::setPhoneState(state));
+}
+
+static int
+android_media_AudioSystem_setRingerMode(JNIEnv *env, jobject thiz, jint mode, jint mask)
+{
+    return check_AudioSystem_Command(AudioSystem::setRingerMode(mode, mask));
+}
+
+static int
+android_media_AudioSystem_setForceUse(JNIEnv *env, jobject thiz, jint usage, jint config)
+{
+    return check_AudioSystem_Command(AudioSystem::setForceUse(static_cast <AudioSystem::force_use>(usage),
+                                                           static_cast <AudioSystem::forced_config>(config)));
+}
+
+static int
+android_media_AudioSystem_getForceUse(JNIEnv *env, jobject thiz, jint usage)
+{
+    return static_cast <int>(AudioSystem::getForceUse(static_cast <AudioSystem::force_use>(usage)));
+}
+
+static int
+android_media_AudioSystem_initStreamVolume(JNIEnv *env, jobject thiz, jint stream, jint indexMin, jint indexMax)
+{
+    return check_AudioSystem_Command(AudioSystem::initStreamVolume(static_cast <AudioSystem::stream_type>(stream),
+                                                                   indexMin,
+                                                                   indexMax));
+}
+
+static int
+android_media_AudioSystem_setStreamVolumeIndex(JNIEnv *env, jobject thiz, jint stream, jint index)
+{
+    return check_AudioSystem_Command(AudioSystem::setStreamVolumeIndex(static_cast <AudioSystem::stream_type>(stream), index));
+}
+
+static int
+android_media_AudioSystem_getStreamVolumeIndex(JNIEnv *env, jobject thiz, jint stream)
+{
+    int index;
+    if (AudioSystem::getStreamVolumeIndex(static_cast <AudioSystem::stream_type>(stream), &index) != NO_ERROR) {
+        index = -1;
+    }
+    return index;
+}
+
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gMethods[] = {
-    {"setVolume",           "(II)I",    (void *)android_media_AudioSystem_setVolume},
-    {"getVolume",           "(I)I",     (void *)android_media_AudioSystem_getVolume},
-    {"setParameter",        "(Ljava/lang/String;Ljava/lang/String;)V", (void *)android_media_AudioSystem_setParameter},
+    {"setParameters",        "(Ljava/lang/String;)I", (void *)android_media_AudioSystem_setParameters},
+    {"getParameters",        "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_AudioSystem_getParameters},
     {"muteMicrophone",      "(Z)I",     (void *)android_media_AudioSystem_muteMicrophone},
     {"isMicrophoneMuted",   "()Z",      (void *)android_media_AudioSystem_isMicrophoneMuted},
-    {"setRouting",          "(III)I",   (void *)android_media_AudioSystem_setRouting},
-    {"getRouting",          "(I)I",     (void *)android_media_AudioSystem_getRouting},
-    {"setMode",             "(I)I",     (void *)android_media_AudioSystem_setMode},
-    {"getMode",             "()I",      (void *)android_media_AudioSystem_getMode},
     {"isMusicActive",       "()Z",      (void *)android_media_AudioSystem_isMusicActive},
+    {"setDeviceConnectionState", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
+    {"getDeviceConnectionState", "(ILjava/lang/String;)I",  (void *)android_media_AudioSystem_getDeviceConnectionState},
+    {"setPhoneState",       "(I)I",     (void *)android_media_AudioSystem_setPhoneState},
+    {"setRingerMode",       "(II)I",    (void *)android_media_AudioSystem_setRingerMode},
+    {"setForceUse",         "(II)I",    (void *)android_media_AudioSystem_setForceUse},
+    {"getForceUse",         "(I)I",     (void *)android_media_AudioSystem_getForceUse},
+    {"initStreamVolume",    "(III)I",   (void *)android_media_AudioSystem_initStreamVolume},
+    {"setStreamVolumeIndex","(II)I",    (void *)android_media_AudioSystem_setStreamVolumeIndex},
+    {"getStreamVolumeIndex","(I)I",     (void *)android_media_AudioSystem_getStreamVolumeIndex}
 };
 
 const char* const kClassPathName = "android/media/AudioSystem";
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index bc7f3f5..6449147 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -103,7 +103,7 @@
 #define AUDIOTRACK_ERROR_BAD_VALUE                 -2
 #define AUDIOTRACK_ERROR_INVALID_OPERATION         -3
 #define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM         -16
-#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELCOUNT -17
+#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK -17
 #define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT       -18
 #define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE   -19
 #define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED    -20
@@ -164,11 +164,11 @@
 // ----------------------------------------------------------------------------
 static int
 android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
-        jint streamType, jint sampleRateInHertz, jint nbChannels, 
+        jint streamType, jint sampleRateInHertz, jint channels,
         jint audioFormat, jint buffSizeInBytes, jint memoryMode)
 {
-    LOGV("sampleRate=%d, audioFormat(from Java)=%d, nbChannels=%d, buffSize=%d", 
-        sampleRateInHertz, audioFormat, nbChannels, buffSizeInBytes);
+    LOGV("sampleRate=%d, audioFormat(from Java)=%d, channels=%x, buffSize=%d",
+        sampleRateInHertz, audioFormat, channels, buffSizeInBytes);
     int afSampleRate;
     int afFrameCount;
 
@@ -181,10 +181,11 @@
         return AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
     }
 
-    if ((nbChannels == 0) || (nbChannels > 2)) {
-        LOGE("Error creating AudioTrack: channel count is not 1 or 2.");
-        return AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELCOUNT;
+    if (!AudioSystem::isOutputChannel(channels)) {
+        LOGE("Error creating AudioTrack: invalid channel mask.");
+        return AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
     }
+    int nbChannels = AudioSystem::popCount(channels);
     
     // check the stream type
     AudioSystem::stream_type atStreamType;
@@ -231,15 +232,7 @@
     int bytesPerSample = audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1;
     int format = audioFormat == javaAudioTrackFields.PCM16 ? 
             AudioSystem::PCM_16_BIT : AudioSystem::PCM_8_BIT;
-    int frameCount;
-    if (buffSizeInBytes == -1) {
-        // compute the frame count based on the system's output frame count 
-        // and the native sample rate
-        frameCount = (sampleRateInHertz*afFrameCount)/afSampleRate;
-    } else {
-        // compute the frame count based on the specified buffer size
-        frameCount = buffSizeInBytes / (nbChannels * bytesPerSample);
-    }
+    int frameCount = buffSizeInBytes / (nbChannels * bytesPerSample);
     
     AudioTrackJniStorage* lpJniStorage = new AudioTrackJniStorage();
     
@@ -271,7 +264,7 @@
             atStreamType,// stream type
             sampleRateInHertz,
             format,// word length, PCM
-            nbChannels,
+            channels,
             frameCount,
             0,// flags
             audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
@@ -291,7 +284,7 @@
             atStreamType,// stream type
             sampleRateInHertz,
             format,// word length, PCM
-            nbChannels,
+            channels,
             frameCount,
             0,// flags
             audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));