Implement channel index masks in AudioDeviceInfo.

Bug: 21146646
Change-Id: I210f6bb4a4ec0ac0820d1823cffe417141725327
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 1cd07d1..ac00532 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -677,13 +677,14 @@
         // constructed by java code with correct class type (device, mix etc...)
         // and reference to AudioPort instance in this client
         jAudioPort = env->NewObject(gAudioPortClass, gAudioPortCstor,
-                                           jHandle,
-                                           0,
-                                           NULL,
-                                           NULL,
-                                           NULL,
-                                           NULL,
-                                           NULL);
+                                           jHandle, // handle
+                                           0,       // role
+                                           NULL,    // name
+                                           NULL,    // samplingRates
+                                           NULL,    // channelMasks
+                                           NULL,    // channelIndexMasks
+                                           NULL,    // formats
+                                           NULL);   // gains
         env->DeleteLocalRef(jHandle);
         if (jAudioPort == NULL) {
             return (jint)AUDIO_JAVA_ERROR;
@@ -837,11 +838,14 @@
     jint jStatus = (jint)AUDIO_JAVA_SUCCESS;
     jintArray jSamplingRates = NULL;
     jintArray jChannelMasks = NULL;
+    jintArray jChannelIndexMasks = NULL;
     jintArray jFormats = NULL;
     jobjectArray jGains = NULL;
     jobject jHandle = NULL;
     jstring jDeviceName = NULL;
     bool useInMask;
+    size_t numPositionMasks = 0;
+    size_t numIndexMasks = 0;
 
     ALOGV("convertAudioPortFromNative id %d role %d type %d name %s",
         nAudioPort->id, nAudioPort->role, nAudioPort->type, nAudioPort->name);
@@ -856,23 +860,43 @@
                                (jint *)nAudioPort->sample_rates);
     }
 
-    jChannelMasks = env->NewIntArray(nAudioPort->num_channel_masks);
+    // count up how many masks are positional and indexed
+    for(size_t index = 0; index < nAudioPort->num_channel_masks; index++) {
+        const audio_channel_mask_t mask = nAudioPort->channel_masks[index];
+        if (audio_channel_mask_get_representation(mask) == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
+            numIndexMasks++;
+        } else {
+            numPositionMasks++;
+        }
+    }
+
+    jChannelMasks = env->NewIntArray(numPositionMasks);
     if (jChannelMasks == NULL) {
         jStatus = (jint)AUDIO_JAVA_ERROR;
         goto exit;
     }
+    jChannelIndexMasks = env->NewIntArray(numIndexMasks);
+    if (jChannelIndexMasks == NULL) {
+        jStatus = (jint)AUDIO_JAVA_ERROR;
+        goto exit;
+    }
     useInMask = useInChannelMask(nAudioPort->type, nAudioPort->role);
 
-    jint jMask;
-    for (size_t j = 0; j < nAudioPort->num_channel_masks; j++) {
-        if (useInMask) {
-            jMask = inChannelMaskFromNative(nAudioPort->channel_masks[j]);
+    // put the masks in the output arrays
+    for (size_t maskIndex = 0, posMaskIndex = 0, indexedMaskIndex = 0;
+         maskIndex < nAudioPort->num_channel_masks; maskIndex++) {
+        const audio_channel_mask_t mask = nAudioPort->channel_masks[maskIndex];
+        if (audio_channel_mask_get_representation(mask) == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
+            jint jMask = audio_channel_mask_get_bits(mask);
+            env->SetIntArrayRegion(jChannelIndexMasks, indexedMaskIndex++, 1, &jMask);
         } else {
-            jMask = outChannelMaskFromNative(nAudioPort->channel_masks[j]);
+            jint jMask = useInMask ? inChannelMaskFromNative(mask)
+                                   : outChannelMaskFromNative(mask);
+            env->SetIntArrayRegion(jChannelMasks, posMaskIndex++, 1, &jMask);
         }
-        env->SetIntArrayRegion(jChannelMasks, j, 1, &jMask);
     }
 
+    // formats
     jFormats = env->NewIntArray(nAudioPort->num_formats);
     if (jFormats == NULL) {
         jStatus = (jint)AUDIO_JAVA_ERROR;
@@ -883,14 +907,17 @@
         env->SetIntArrayRegion(jFormats, j, 1, &jFormat);
     }
 
+    // gains
     jGains = env->NewObjectArray(nAudioPort->num_gains,
                                           gAudioGainClass, NULL);
     if (jGains == NULL) {
         jStatus = (jint)AUDIO_JAVA_ERROR;
         goto exit;
     }
+
     for (size_t j = 0; j < nAudioPort->num_gains; j++) {
         audio_channel_mask_t nMask = nAudioPort->gains[j].channel_mask;
+        jint jMask;
         if (useInMask) {
             jMask = inChannelMaskFromNative(nMask);
             ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
@@ -931,7 +958,8 @@
         jstring jAddress = env->NewStringUTF(nAudioPort->ext.device.address);
         *jAudioPort = env->NewObject(gAudioDevicePortClass, gAudioDevicePortCstor,
                                      jHandle, jDeviceName,
-                                     jSamplingRates, jChannelMasks, jFormats, jGains,
+                                     jSamplingRates, jChannelMasks, jChannelIndexMasks,
+                                     jFormats, jGains,
                                      nAudioPort->ext.device.type, jAddress);
         env->DeleteLocalRef(jAddress);
     } else if (nAudioPort->type == AUDIO_PORT_TYPE_MIX) {
@@ -939,7 +967,7 @@
         *jAudioPort = env->NewObject(gAudioMixPortClass, gAudioMixPortCstor,
                                      jHandle, nAudioPort->ext.mix.handle,
                                      nAudioPort->role, jDeviceName,
-                                     jSamplingRates, jChannelMasks,
+                                     jSamplingRates, jChannelMasks, jChannelIndexMasks,
                                      jFormats, jGains);
     } else {
         ALOGE("convertAudioPortFromNative unknown nAudioPort type %d", nAudioPort->type);
@@ -1634,7 +1662,7 @@
     jclass audioPortClass = FindClassOrDie(env, "android/media/AudioPort");
     gAudioPortClass = MakeGlobalRefOrDie(env, audioPortClass);
     gAudioPortCstor = GetMethodIDOrDie(env, audioPortClass, "<init>",
-            "(Landroid/media/AudioHandle;ILjava/lang/String;[I[I[I[Landroid/media/AudioGain;)V");
+            "(Landroid/media/AudioHandle;ILjava/lang/String;[I[I[I[I[Landroid/media/AudioGain;)V");
     gAudioPortFields.mHandle = GetFieldIDOrDie(env, audioPortClass, "mHandle",
                                                "Landroid/media/AudioHandle;");
     gAudioPortFields.mRole = GetFieldIDOrDie(env, audioPortClass, "mRole", "I");
@@ -1672,12 +1700,12 @@
     jclass audioDevicePortClass = FindClassOrDie(env, "android/media/AudioDevicePort");
     gAudioDevicePortClass = MakeGlobalRefOrDie(env, audioDevicePortClass);
     gAudioDevicePortCstor = GetMethodIDOrDie(env, audioDevicePortClass, "<init>",
-            "(Landroid/media/AudioHandle;Ljava/lang/String;[I[I[I[Landroid/media/AudioGain;ILjava/lang/String;)V");
+            "(Landroid/media/AudioHandle;Ljava/lang/String;[I[I[I[I[Landroid/media/AudioGain;ILjava/lang/String;)V");
 
     jclass audioMixPortClass = FindClassOrDie(env, "android/media/AudioMixPort");
     gAudioMixPortClass = MakeGlobalRefOrDie(env, audioMixPortClass);
     gAudioMixPortCstor = GetMethodIDOrDie(env, audioMixPortClass, "<init>",
-            "(Landroid/media/AudioHandle;IILjava/lang/String;[I[I[I[Landroid/media/AudioGain;)V");
+            "(Landroid/media/AudioHandle;IILjava/lang/String;[I[I[I[I[Landroid/media/AudioGain;)V");
 
     jclass audioGainClass = FindClassOrDie(env, "android/media/AudioGain");
     gAudioGainClass = MakeGlobalRefOrDie(env, audioGainClass);
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index 431d37e..173d349 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -173,8 +173,7 @@
      * @see AudioFormat
      */
     public @NonNull int[] getChannelIndexMasks() {
-        // TODO: implement
-        return new int[0];
+        return mPort.channelIndexMasks();
     }
 
     /**
diff --git a/media/java/android/media/AudioDevicePort.java b/media/java/android/media/AudioDevicePort.java
index c078260..aea39a3 100644
--- a/media/java/android/media/AudioDevicePort.java
+++ b/media/java/android/media/AudioDevicePort.java
@@ -37,12 +37,12 @@
     private final String mAddress;
 
     AudioDevicePort(AudioHandle handle, String deviceName,
-            int[] samplingRates, int[] channelMasks,
+            int[] samplingRates, int[] channelMasks, int[] channelIndexMasks,
             int[] formats, AudioGain[] gains, int type, String address) {
         super(handle,
              (AudioManager.isInputDevice(type) == true)  ?
                         AudioPort.ROLE_SOURCE : AudioPort.ROLE_SINK,
-             deviceName, samplingRates, channelMasks, formats, gains);
+             deviceName, samplingRates, channelMasks, channelIndexMasks, formats, gains);
         mType = type;
         mAddress = address;
     }
diff --git a/media/java/android/media/AudioMixPort.java b/media/java/android/media/AudioMixPort.java
index ab55c8d..ba144bf 100644
--- a/media/java/android/media/AudioMixPort.java
+++ b/media/java/android/media/AudioMixPort.java
@@ -31,9 +31,10 @@
     private final int mIoHandle;
 
     AudioMixPort(AudioHandle handle, int ioHandle, int role, String deviceName,
-            int[] samplingRates, int[] channelMasks,
+            int[] samplingRates, int[] channelMasks, int[] channelIndexMasks,
             int[] formats, AudioGain[] gains) {
-        super(handle, role, deviceName, samplingRates, channelMasks, formats, gains);
+        super(handle, role, deviceName, samplingRates, channelMasks, channelIndexMasks,
+                formats, gains);
         mIoHandle = ioHandle;
     }
 
diff --git a/media/java/android/media/AudioPort.java b/media/java/android/media/AudioPort.java
index 7328d7a..19bf51d 100644
--- a/media/java/android/media/AudioPort.java
+++ b/media/java/android/media/AudioPort.java
@@ -71,12 +71,13 @@
     private final String mName;
     private final int[] mSamplingRates;
     private final int[] mChannelMasks;
+    private final int[] mChannelIndexMasks;
     private final int[] mFormats;
     private final AudioGain[] mGains;
     private AudioPortConfig mActiveConfig;
 
     AudioPort(AudioHandle handle, int role, String name,
-            int[] samplingRates, int[] channelMasks,
+            int[] samplingRates, int[] channelMasks, int[] channelIndexMasks,
             int[] formats, AudioGain[] gains) {
 
         mHandle = handle;
@@ -84,6 +85,7 @@
         mName = name;
         mSamplingRates = samplingRates;
         mChannelMasks = channelMasks;
+        mChannelIndexMasks = channelIndexMasks;
         mFormats = formats;
         mGains = gains;
     }
@@ -133,6 +135,15 @@
     }
 
     /**
+     * Get the list of supported channel index mask configurations
+     * (e.g 0x0003 means 2 channel, 0x000F means 4 channel....)
+     * Empty array if channel index mask is not relevant for this audio port
+     */
+    public int[] channelIndexMasks() {
+        return mChannelIndexMasks;
+    }
+
+    /**
      * Get the list of supported audio format configurations
      * (e.g AudioFormat.ENCODING_PCM_16BIT)
      * Empty array if format is not relevant for this audio port