hal: fix USB HIFI profile dynamic properties reporting

Fix several problems with reporting of USB device properties
by HIFI profiles:
- Allow max 8 channels and 32 bit format for USB HIFI profiles
- Do not only report one channel mask corresponding to maximum channel
count but all possible channel masks
- Do not apply default properties in open_input_stream for HIFI USB
profile as the defaults are set by read_usb_sup_params_and_compare()

Bug: 38423100
Test: verify properties reporting with various USB devices
Change-Id: Ib3056428713a6f5c6cc108b0de24ca9438c62e7f
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index b885841..2224e7e 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -86,6 +86,7 @@
 #define XSTR(x) STR(x)
 #define STR(x) #x
 #endif
+#define MAX_HIFI_CHANNEL_COUNT 8
 
 #define ULL_PERIOD_SIZE (DEFAULT_OUTPUT_SAMPLING_RATE/1000)
 
@@ -299,8 +300,17 @@
     STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO),
     STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
     STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
+    STRING_TO_ENUM(AUDIO_CHANNEL_IN_MONO),
     STRING_TO_ENUM(AUDIO_CHANNEL_IN_STEREO),
-    //TBD - string values for channel_in > 2?
+    STRING_TO_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
+    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_1),
+    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_2),
+    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_3),
+    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_4),
+    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_5),
+    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_6),
+    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_7),
+    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_8),
 };
 
 static int set_voice_volume_l(struct audio_device *adev, float volume);
@@ -1011,19 +1021,39 @@
 
 static int read_usb_sup_channel_masks(bool is_playback,
                                       audio_channel_mask_t *supported_channel_masks,
-                                      uint32_t max_masks __unused)
+                                      uint32_t max_masks)
 {
     int channels = audio_extn_usb_get_max_channels(is_playback);
-    if (is_playback) {
-        supported_channel_masks[0] =
-                channels < 3 ? audio_channel_out_mask_from_count(channels) :
-                               audio_channel_mask_for_index_assignment_from_count(channels);
-    } else {
-        supported_channel_masks[0] = audio_channel_in_mask_from_count(channels);
+    int channel_count;
+    uint32_t num_masks = 0;
+    if (channels > MAX_HIFI_CHANNEL_COUNT) {
+        channels = MAX_HIFI_CHANNEL_COUNT;
     }
-    ALOGV("%s: %s supported ch %d", __func__,
-          is_playback ? "P" : "C", channels);
-    return 1;
+    if (is_playback) {
+        // For playback we never report mono because the framework always outputs stereo
+        channel_count = DEFAULT_CHANNEL_COUNT;
+        // audio_channel_out_mask_from_count() does return positional masks for channel counts
+        // above 2 but we want indexed masks here. So we
+        for ( ; channel_count <= channels && num_masks < max_masks; channel_count++) {
+            supported_channel_masks[num_masks++] = audio_channel_out_mask_from_count(channel_count);
+        }
+        for ( ; channel_count <= channels && num_masks < max_masks; channel_count++) {
+            supported_channel_masks[num_masks++] =
+                    audio_channel_mask_for_index_assignment_from_count(channel_count);
+        }
+    } else {
+        // For capture we report all supported channel masks from 1 channel up.
+        channel_count = MIN_CHANNEL_COUNT;
+        // audio_channel_in_mask_from_count() does the right conversion to either positional or
+        // indexed mask
+        for ( ; channel_count <= channels && num_masks < max_masks; channel_count++) {
+            supported_channel_masks[num_masks++] =
+                    audio_channel_in_mask_from_count(channel_count);
+        }
+    }
+    ALOGV("%s: %s supported ch %d supported_channel_masks[0] %08x num_masks %d", __func__,
+          is_playback ? "P" : "C", channels, supported_channel_masks[0], num_masks);
+    return num_masks;
 }
 
 static int read_usb_sup_formats(bool is_playback __unused,
@@ -1069,6 +1099,7 @@
                                        max_formats);
     num_masks = read_usb_sup_channel_masks(is_playback, supported_channel_masks,
                                            max_masks);
+
     num_rates = read_usb_sup_sample_rates(is_playback,
                                           supported_sample_rates, max_rates);
 
@@ -1896,18 +1927,20 @@
 
 static int check_input_parameters(uint32_t sample_rate,
                                   audio_format_t format,
-                                  int channel_count)
+                                  int channel_count, bool is_usb_hifi)
 {
     if ((format != AUDIO_FORMAT_PCM_16_BIT) &&
         (format != AUDIO_FORMAT_PCM_8_24_BIT) &&
-        (format != AUDIO_FORMAT_PCM_24_BIT_PACKED)) {
+        (format != AUDIO_FORMAT_PCM_24_BIT_PACKED) &&
+        !(is_usb_hifi && (format == AUDIO_FORMAT_PCM_32_BIT))) {
         ALOGE("%s: unsupported AUDIO FORMAT (%d) ", __func__, format);
         return -EINVAL;
     }
 
-    if ((channel_count < MIN_CHANNEL_COUNT) || (channel_count > MAX_CHANNEL_COUNT)) {
+    int max_channel_count = is_usb_hifi ? MAX_HIFI_CHANNEL_COUNT : MAX_CHANNEL_COUNT;
+    if ((channel_count < MIN_CHANNEL_COUNT) || (channel_count > max_channel_count)) {
         ALOGE("%s: unsupported channel count (%d) passed  Min / Max (%d / %d)", __func__,
-               channel_count, MIN_CHANNEL_COUNT, MAX_CHANNEL_COUNT);
+               channel_count, MIN_CHANNEL_COUNT, max_channel_count);
         return -EINVAL;
     }
 
@@ -1939,9 +1972,6 @@
 {
     size_t size = 0;
 
-    if (check_input_parameters(sample_rate, format, channel_count) != 0)
-        return 0;
-
     size = (sample_rate * duration_ms) / 1000;
     if (is_low_latency)
         size = configured_low_latency_capture_period_size;
@@ -4091,6 +4121,11 @@
 {
     int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
 
+    /* Don't know if USB HIFI in this context so use true to be conservative */
+    if (check_input_parameters(config->sample_rate, config->format, channel_count,
+                               true /*is_usb_hifi */) != 0)
+        return 0;
+
     return get_stream_buffer_size(AUDIO_CAPTURE_PERIOD_DURATION_MSEC,
                                  config->sample_rate, config->format,
                                  channel_count,
@@ -4145,25 +4180,29 @@
     struct audio_device *adev = (struct audio_device *)dev;
     struct stream_in *in;
     int ret = 0, buffer_size, frame_size;
-    int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
+    int channel_count;
     bool is_low_latency = false;
     bool is_usb_dev = audio_is_usb_in_device(devices);
     bool may_use_hifi_record = adev_input_allow_hifi_record(adev,
                                                             devices,
                                                             flags,
                                                             source);
-    ALOGE("%s: enter", __func__);
+    ALOGV("%s: enter", __func__);
     *stream_in = NULL;
 
-    if (config->sample_rate == 0)
-        config->sample_rate = DEFAULT_INPUT_SAMPLING_RATE;
-    if (config->channel_mask == AUDIO_CHANNEL_NONE)
-        config->channel_mask = AUDIO_CHANNEL_IN_MONO;
-    if (config->format == AUDIO_FORMAT_DEFAULT)
-        config->format = AUDIO_FORMAT_PCM_16_BIT;
+    if (!(is_usb_dev && may_use_hifi_record)) {
+        if (config->sample_rate == 0)
+            config->sample_rate = DEFAULT_INPUT_SAMPLING_RATE;
+        if (config->channel_mask == AUDIO_CHANNEL_NONE)
+            config->channel_mask = AUDIO_CHANNEL_IN_MONO;
+        if (config->format == AUDIO_FORMAT_DEFAULT)
+            config->format = AUDIO_FORMAT_PCM_16_BIT;
 
-    if (check_input_parameters(config->sample_rate, config->format, channel_count) != 0)
-        return -EINVAL;
+        channel_count = audio_channel_count_from_in_mask(config->channel_mask);
+
+        if (check_input_parameters(config->sample_rate, config->format, channel_count, false) != 0)
+            return -EINVAL;
+    }
 
     if (audio_extn_tfa_98xx_is_supported() &&
         (audio_extn_hfp_is_active(adev) || voice_is_in_call(adev)))
@@ -4195,7 +4234,6 @@
     in->source = source;
     in->dev = adev;
     in->standby = 1;
-    in->channel_mask = config->channel_mask;
     in->capture_handle = handle;
     in->flags = flags;
 
@@ -4216,6 +4254,7 @@
             ret = -EINVAL;
             goto err_open;
         }
+        channel_count = audio_channel_count_from_in_mask(config->channel_mask);
     } else if (config->format == AUDIO_FORMAT_DEFAULT) {
         config->format = AUDIO_FORMAT_PCM_16_BIT;
     } else if (config->format == AUDIO_FORMAT_PCM_FLOAT ||
@@ -4246,6 +4285,7 @@
     }
 
     in->format = config->format;
+    in->channel_mask = config->channel_mask;
 
     /* Update config params with the requested sample rate and channels */
     if (in->device == AUDIO_DEVICE_IN_TELEPHONY_RX) {