hal: Restrict SSR recording to channel position representation

Surround Sound Recording(SSR) supports only channel position
representation while default channel mask for multi-channel
recording is always index representation.
Return updated channel mask in case index representation is sent
for channel count 6. This ensures audio flinger reopens the session
with updated position representation channel mask.
And also handled the case if any client requests recording with
multichannel when SSR is not enabled, will check the max_mic_count
supported by the device and update the channel mask accordingly.

Change-Id: Ib925a5f31d50182cd595e547f3412ed809224a5a
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 65f516c..e46b736 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -1142,3 +1142,52 @@
     }
 }
 #endif /* KPI_OPTIMIZE_ENABLED */
+
+static int audio_extn_set_multichannel_mask(struct audio_device *adev,
+                                            struct stream_in *in,
+                                            struct audio_config *config,
+                                            bool *channel_mask_updated)
+{
+    int ret = -EINVAL;
+    int channel_count = audio_channel_count_from_in_mask(in->channel_mask);
+    *channel_mask_updated = false;
+
+    int max_mic_count = platform_get_max_mic_count(adev->platform);
+    /* validate input params*/
+    if ((channel_count == 6) &&
+        (in->format == AUDIO_FORMAT_PCM_16_BIT)) {
+
+        switch (max_mic_count) {
+            case 4:
+                config->channel_mask = AUDIO_CHANNEL_INDEX_MASK_4;
+                break;
+            case 3:
+                config->channel_mask = AUDIO_CHANNEL_INDEX_MASK_3;
+                break;
+            case 2:
+                config->channel_mask = AUDIO_CHANNEL_IN_STEREO;
+                break;
+            default:
+                config->channel_mask = AUDIO_CHANNEL_IN_STEREO;
+                break;
+        }
+        ret = 0;
+        *channel_mask_updated = true;
+    }
+    return ret;
+}
+
+int audio_extn_check_and_set_multichannel_usecase(struct audio_device *adev,
+                                                  struct stream_in *in,
+                                                  struct audio_config *config,
+                                                  bool *update_params)
+{
+    bool ssr_supported = false;
+    ssr_supported = audio_extn_ssr_check_usecase(in);
+    if (ssr_supported) {
+        return audio_extn_ssr_set_usecase(in, config, update_params);
+    } else {
+        return audio_extn_set_multichannel_mask(adev, in, config,
+                                                update_params);
+    }
+}
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 069feda..8ce06d9 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -189,17 +189,21 @@
 #endif
 
 #ifndef SSR_ENABLED
-#define audio_extn_ssr_check_and_set_usecase(in)      (-1)
-#define audio_extn_ssr_init(in, num_out_chan)         (0)
-#define audio_extn_ssr_deinit()                       (0)
-#define audio_extn_ssr_update_enabled()               (0)
-#define audio_extn_ssr_get_enabled()                  (0)
-#define audio_extn_ssr_read(stream, buffer, bytes)    (0)
-#define audio_extn_ssr_set_parameters(adev, parms)    (0)
-#define audio_extn_ssr_get_parameters(adev, parms, reply) (0)
-#define audio_extn_ssr_get_stream()                   (0)
+#define audio_extn_ssr_check_usecase(in)                                  (0)
+#define audio_extn_ssr_set_usecase(in, config, channel_mask_updated)      (0)
+#define audio_extn_ssr_init(in, num_out_chan)                             (0)
+#define audio_extn_ssr_deinit()                                           (0)
+#define audio_extn_ssr_update_enabled()                                   (0)
+#define audio_extn_ssr_get_enabled()                                      (0)
+#define audio_extn_ssr_read(stream, buffer, bytes)                        (0)
+#define audio_extn_ssr_set_parameters(adev, parms)                        (0)
+#define audio_extn_ssr_get_parameters(adev, parms, reply)                 (0)
+#define audio_extn_ssr_get_stream()                                       (0)
 #else
-int audio_extn_ssr_check_and_set_usecase(struct stream_in *in);
+bool audio_extn_ssr_check_usecase(struct stream_in *in);
+int audio_extn_ssr_set_usecase(struct stream_in *in,
+                                         struct audio_config *config,
+                                         bool *channel_mask_updated);
 int32_t audio_extn_ssr_init(struct stream_in *in,
                             int num_out_chan);
 int32_t audio_extn_ssr_deinit();
@@ -214,6 +218,10 @@
                                    struct str_parms *reply);
 struct stream_in *audio_extn_ssr_get_stream();
 #endif
+int audio_extn_check_and_set_multichannel_usecase(struct audio_device *adev,
+                                                  struct stream_in *in,
+                                                  struct audio_config *config,
+                                                  bool *update_params);
 
 #ifndef HW_VARIANTS_ENABLED
 #define hw_info_init(snd_card_name)                      (0)
diff --git a/hal/audio_extn/ssr.c b/hal/audio_extn/ssr.c
index f55f3ce..51a6a26 100644
--- a/hal/audio_extn/ssr.c
+++ b/hal/audio_extn/ssr.c
@@ -331,33 +331,55 @@
     return false;
 }
 
-int audio_extn_ssr_check_and_set_usecase(struct stream_in *in)
-{
-    int ret = -1;
+bool  audio_extn_ssr_check_usecase(struct stream_in *in) {
+    int ret = false;
     int channel_count = audio_channel_count_from_in_mask(in->channel_mask);
     audio_devices_t devices = in->device;
     audio_source_t source = in->source;
 
-    /* validate input params
-     * only stereo and 5:1 channel config is supported
-     * only AUDIO_DEVICE_IN_BUILTIN_MIC, AUDIO_DEVICE_IN_BACK_MIC supports 3 mics */
-    if (audio_extn_ssr_get_enabled() &&
-           ((channel_count == 2) || (channel_count == 6)) &&
-           ((AUDIO_SOURCE_MIC == source) || (AUDIO_SOURCE_CAMCORDER == source)) &&
-           ((AUDIO_DEVICE_IN_BUILTIN_MIC == devices) || (AUDIO_DEVICE_IN_BACK_MIC == devices)) &&
-           (in->format == AUDIO_FORMAT_PCM_16_BIT)) {
-
-        ALOGD("%s: Found SSR use case starting SSR lib with channel_count :%d",
+    if ((audio_extn_ssr_get_enabled()) &&
+            ((channel_count == 2) || (channel_count == 6)) &&
+            ((AUDIO_SOURCE_MIC == source) || (AUDIO_SOURCE_CAMCORDER == source)) &&
+            ((AUDIO_DEVICE_IN_BUILTIN_MIC == devices) || (AUDIO_DEVICE_IN_BACK_MIC == devices)) &&
+            (in->format == AUDIO_FORMAT_PCM_16_BIT)) {
+        ALOGD("%s: SSR enabled with channel_count :%d",
                       __func__, channel_count);
+        ret = true;
+    }
+    return ret;
+}
 
-        if (!audio_extn_ssr_init(in, channel_count)) {
-            ALOGD("%s: Created SSR session succesfully", __func__);
+int audio_extn_ssr_set_usecase(struct stream_in *in,
+                               struct audio_config *config,
+                               bool *update_params)
+{
+    int ret = -EINVAL;
+    int channel_count = audio_channel_count_from_in_mask(in->channel_mask);
+    audio_channel_representation_t representation =
+                  audio_channel_mask_get_representation(in->channel_mask);
+    *update_params = false;
+
+    if (audio_extn_ssr_check_usecase(in)) {
+
+        if (representation == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
+            /* update params in case channel representation index.
+             * on returning error, flinger will retry with supported representation passed
+             */
+            ALOGD("%s: SSR supports only channel representation position, channel_mask(%#x)"
+                              ,__func__, config->channel_mask);
+            config->channel_mask = AUDIO_CHANNEL_IN_5POINT1;
             ret = 0;
+            *update_params = true;
         } else {
-            ALOGE("%s: Unable to start SSR record session", __func__);
+            if (!audio_extn_ssr_init(in, channel_count)) {
+                ALOGD("%s: Created SSR session succesfully", __func__);
+                ret = 0;
+            } else {
+                ALOGE("%s: Unable to start SSR record session", __func__);
+            }
         }
-   }
-   return ret;
+    }
+    return ret;
 }
 
 static void pcm_buffer_queue_push(struct pcm_buffer_queue **queue,
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index f6e11e8..569948a 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -4348,6 +4348,7 @@
     int ret = 0, buffer_size, frame_size;
     int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
     bool is_low_latency = false;
+    bool channel_mask_updated = false;
 
     *stream_in = NULL;
     if (check_input_parameters(config->sample_rate, config->format, channel_count) != 0) {
@@ -4442,7 +4443,14 @@
         in->config.channels = channel_count;
         in->config.rate = config->sample_rate;
         in->sample_rate = config->sample_rate;
-    } else if (!audio_extn_ssr_check_and_set_usecase(in)) {
+    } else if (!audio_extn_check_and_set_multichannel_usecase(adev,
+                in, config, &channel_mask_updated)) {
+        if (channel_mask_updated == true) {
+            ALOGD("%s: return error to retry with updated channel mask (%#x)",
+                   __func__, config->channel_mask);
+            ret = -EINVAL;
+            goto err_open;
+        }
         ALOGD("%s: created surround sound session succesfully",__func__);
     } else if (audio_extn_compr_cap_enabled() &&
             audio_extn_compr_cap_format_supported(config->format) &&
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 47f251f..0296acc 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -5686,3 +5686,8 @@
 {
     return -ENOSYS;
 }
+
+int platform_get_max_mic_count(void *platform) {
+    struct platform_data *my_data = (struct platform_data *)platform;
+    return my_data->max_mic_count;
+}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 48bb46c..a52e2b1 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -5825,3 +5825,8 @@
 ERROR_RETURN:
     return ret;
 }
+
+int platform_get_max_mic_count(void *platform) {
+    struct platform_data *my_data = (struct platform_data *)platform;
+    return my_data->max_mic_count;
+}
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 7bd6756..c3b76b0 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -178,4 +178,5 @@
     void* data, int* length);
 
 unsigned char* platform_get_license(void* platform, int* size);
+int platform_get_max_mic_count(void *platform);
 #endif // AUDIO_PLATFORM_API_H