hal: Fix mute issue for unsupported sample rate in passthru mode

-Mute is observed when passthrough session is opened with
 unsupported sampling rate
-Return error when stream sampling rate is not supported
 by the sink during compress passthrough playback
-Add correct condiiton check for convert usecases

Change-Id: Iea236f5076617a583b7882741b76468294fac013
CRs-fixed: 2096943
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index c30f982..117d270 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -465,12 +465,10 @@
 
 
 #if defined(DS1_DOLBY_DDP_ENABLED) || defined(DS2_DOLBY_DAP_ENABLED)
-bool audio_extn_is_dolby_format(audio_format_t format);
 int audio_extn_dolby_get_snd_codec_id(struct audio_device *adev,
                                       struct stream_out *out,
                                       audio_format_t format);
 #else
-#define audio_extn_is_dolby_format(format)              (0)
 #define audio_extn_dolby_get_snd_codec_id(adev, out, format)       (0)
 #endif
 
@@ -518,6 +516,7 @@
 #define audio_extn_passthru_get_channel_count(out) (0)
 #define audio_extn_passthru_update_dts_stream_configuration(out, buffer, bytes) (-ENOSYS)
 #define audio_extn_passthru_is_direct_passthrough(out)	(0)
+#define audio_extn_passthru_is_supported_backend_edid_cfg(adev, out) (0)
 #else
 bool audio_extn_passthru_is_convert_supported(struct audio_device *adev,
                                                  struct stream_out *out);
@@ -545,6 +544,8 @@
 int audio_extn_passthru_update_dts_stream_configuration(struct stream_out *out,
         const void *buffer, size_t bytes);
 bool audio_extn_passthru_is_direct_passthrough(struct stream_out *out);
+bool audio_extn_passthru_is_supported_backend_edid_cfg(struct audio_device *adev,
+                                                   struct stream_out *out);
 #endif
 
 #ifndef HFP_ENABLED
@@ -621,6 +622,7 @@
                                   struct audio_usecase *usecase);
 int audio_extn_utils_get_snd_card_num();
 bool audio_extn_is_dsp_bit_width_enforce_mode_supported(audio_output_flags_t flags);
+bool audio_extn_utils_is_dolby_format(audio_format_t format);
 
 #ifdef DS2_DOLBY_DAP_ENABLED
 #define LIB_DS2_DAP_HAL "vendor/lib/libhwdaphal.so"
diff --git a/hal/audio_extn/dolby.c b/hal/audio_extn/dolby.c
index bc7aa5c..fda9a1a 100644
--- a/hal/audio_extn/dolby.c
+++ b/hal/audio_extn/dolby.c
@@ -362,19 +362,6 @@
 }
 #endif /* DS1_DOLBY_DDP_ENABLED */
 
-#if defined(DS1_DOLBY_DDP_ENABLED) || defined(DS2_DOLBY_DAP_ENABLED)
-bool audio_extn_is_dolby_format(audio_format_t format)
-{
-    if (format == AUDIO_FORMAT_AC3 ||
-            format == AUDIO_FORMAT_E_AC3 ||
-            format == AUDIO_FORMAT_E_AC3_JOC)
-        return true;
-    else
-        return false;
-}
-#endif /* DS1_DOLBY_DDP_ENABLED || DS2_DOLBY_DAP_ENABLED */
-
-
 #ifdef DS1_DOLBY_DAP_ENABLED
 void audio_extn_dolby_set_endpoint(struct audio_device *adev)
 {
diff --git a/hal/audio_extn/passthru.c b/hal/audio_extn/passthru.c
index 701084a..8acffda 100644
--- a/hal/audio_extn/passthru.c
+++ b/hal/audio_extn/passthru.c
@@ -348,11 +348,13 @@
     switch (out->format) {
     case AUDIO_FORMAT_E_AC3:
     case AUDIO_FORMAT_E_AC3_JOC:
-    case AUDIO_FORMAT_DTS_HD:
         if (!platform_is_edid_supported_format(adev->platform,
-            out->format)) {
-            ALOGD("%s:PASSTHROUGH_CONVERT supported", __func__);
-            convert = true;
+                                               out->format)) {
+            if (platform_is_edid_supported_format(adev->platform,
+                                                  AUDIO_FORMAT_AC3)) {
+                ALOGD("%s:PASSTHROUGH_CONVERT supported", __func__);
+                convert = true;
+            }
         }
         break;
     default:
@@ -449,7 +451,7 @@
                         out->format)) {
                     ALOGV("%s : return true",__func__);
                     return true;
-                } else if (audio_extn_is_dolby_format(out->format) &&
+                } else if (audio_extn_utils_is_dolby_format(out->format) &&
                             platform_is_edid_supported_format(out->dev->platform,
                                 AUDIO_FORMAT_AC3)){
                     //return true for EAC3/EAC3_JOC formats
@@ -504,3 +506,44 @@
 {
     return platform_set_device_params(out, DEVICE_PARAM_LATENCY_ID, latency);
 }
+
+bool audio_extn_passthru_is_supported_backend_edid_cfg(struct audio_device *adev,
+                                                   struct stream_out *out)
+{
+    struct audio_backend_cfg backend_cfg;
+    snd_device_t out_snd_device = SND_DEVICE_NONE;
+    int max_edid_channels = platform_edid_get_max_channels(out->dev->platform);
+
+    out_snd_device = platform_get_output_snd_device(adev->platform, out);
+
+    if (platform_get_codec_backend_cfg(adev, out_snd_device, &backend_cfg)) {
+        ALOGE("%s: ERROR: Unable to get current backend config!!!", __func__);
+        return false;
+    }
+
+    ALOGV("%s:becf: afe: bitwidth %d, samplerate %d channels %d format %d"
+          ", device (%s)", __func__,  backend_cfg.bit_width,
+          backend_cfg.sample_rate, backend_cfg.channels, backend_cfg.format,
+          platform_get_snd_device_name(out_snd_device));
+
+    /* Check if the channels are supported */
+    if (max_edid_channels < backend_cfg.channels) {
+
+        ALOGE("%s: ERROR: Unsupported channels in passthru mode!!!"
+              " max_edid_channels - %d backend_channels - %d",
+              __func__, max_edid_channels, backend_cfg.channels);
+        return false;
+    }
+
+    /* Check if the sample rate supported */
+    if (!platform_is_edid_supported_sample_rate(adev->platform,
+                                       backend_cfg.sample_rate)) {
+
+        ALOGE("%s: ERROR: Unsupported sample rate in passthru mode!!!"
+              " backend_samplerate - %d",
+              __func__, backend_cfg.sample_rate);
+        return false;
+    }
+
+    return true;
+}
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index 8ee5948..c1cc9ee 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -1676,7 +1676,7 @@
     struct mixer_ctl *ctl;
     ALOGV("%s: buffer %s bytes %zd", __func__, buffer, bytes);
 #ifdef HDMI_PASSTHROUGH_ENABLED
-    if (audio_extn_is_dolby_format(out->format) &&
+    if (audio_extn_utils_is_dolby_format(out->format) &&
         /*TODO:Extend code to support DTS passthrough*/
         /*set compressed channel status bits*/
         audio_extn_passthru_is_passthrough_stream(out)){
@@ -2351,3 +2351,15 @@
 exit:
     return ret;
 }
+
+bool audio_extn_utils_is_dolby_format(audio_format_t format)
+{
+    if (format == AUDIO_FORMAT_AC3 ||
+            format == AUDIO_FORMAT_E_AC3 ||
+            format == AUDIO_FORMAT_E_AC3_JOC)
+        return true;
+    else
+        return false;
+}
+
+
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 4b698b8..a7d36c6 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -2781,7 +2781,7 @@
                                              out->playback_started);
 
 #ifdef DS1_DOLBY_DDP_ENABLED
-        if (audio_extn_is_dolby_format(out->format))
+        if (audio_extn_utils_is_dolby_format(out->format))
             audio_extn_dolby_send_ddp_endp_params(adev);
 #endif
         if (!(audio_extn_passthru_is_passthrough_stream(out)) &&
@@ -3762,6 +3762,13 @@
             audio_extn_passthru_is_passthrough_stream(out)) {
             audio_extn_passthru_update_stream_configuration(adev, out,
                     buffer, bytes);
+    if ((out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
+         !out->is_iec61937_info_available) {
+
+        if (!audio_extn_passthru_is_passthrough_stream(out)) {
+            out->is_iec61937_info_available = true;
+        } else if (audio_extn_passthru_is_enabled()) {
+            audio_extn_passthru_update_stream_configuration(adev, out, buffer, bytes);
             out->is_iec61937_info_available = true;
 
             if((out->format == AUDIO_FORMAT_DTS) ||
@@ -3773,7 +3780,7 @@
                         out->is_iec61937_info_available = false;
                         ALOGD("iec61937 transmission info not yet updated retry");
                     }
-                } else {
+                } else if (!out->standby) {
                     /* if stream has started and after that there is
                      * stream config change (iec transmission config)
                      * then trigger select_device to update backend configuration.
@@ -3781,6 +3788,10 @@
                     out->stream_config_changed = true;
                     pthread_mutex_lock(&adev->lock);
                     select_devices(adev, out->usecase);
+                    if (!audio_extn_passthru_is_supported_backend_edid_cfg(adev, out)) {
+                        ret = -EINVAL;
+                        goto exit;
+                    }
                     pthread_mutex_unlock(&adev->lock);
                     out->stream_config_changed = false;
                     out->is_iec61937_info_available = true;
@@ -3795,6 +3806,7 @@
                     goto exit;
             }
         }
+       }
     }
 
     if ((out->devices & AUDIO_DEVICE_OUT_ALL_A2DP) &&
@@ -3826,6 +3838,13 @@
             audio_hw_send_gain_dep_calibration(last_known_cal_step);
             last_known_cal_step = -1;
         }
+
+        if ((out->is_iec61937_info_available == true) &&
+            (audio_extn_passthru_is_passthrough_stream(out))&&
+            (!audio_extn_passthru_is_supported_backend_edid_cfg(adev, out))) {
+            ret = -EINVAL;
+            goto exit;
+        }
     }
 
     if (adev->is_channel_status_set == false && (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)){
@@ -5197,7 +5216,7 @@
         out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
 
         out->compr_config.codec->id = get_snd_codec_id(config->offload_info.format);
-        if (audio_extn_is_dolby_format(config->offload_info.format)) {
+        if (audio_extn_utils_is_dolby_format(config->offload_info.format)) {
             audio_extn_dolby_send_ddp_endp_params(adev);
             audio_extn_dolby_set_dmid(adev);
         }
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index d000a7d..3e7b69c 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -5564,6 +5564,33 @@
 }
 
 /*
+ * Get the backend configuration for current snd device
+ */
+int platform_get_codec_backend_cfg(struct audio_device* adev,
+                         snd_device_t snd_device,
+                         struct audio_backend_cfg *backend_cfg)
+{
+    int backend_idx = platform_get_backend_index(snd_device);
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
+
+    backend_cfg->bit_width = my_data->current_backend_cfg[backend_idx].bit_width;
+    backend_cfg->sample_rate =
+                       my_data->current_backend_cfg[backend_idx].sample_rate;
+    backend_cfg->channels =
+                       my_data->current_backend_cfg[backend_idx].channels;
+    backend_cfg->format =
+                       my_data->current_backend_cfg[backend_idx].format;
+
+    ALOGV("%s:becf: afe: bitwidth %d, samplerate %d channels %d format %d"
+          ", backend_idx %d device (%s)", __func__,  backend_cfg->bit_width,
+          backend_cfg->sample_rate, backend_cfg->channels, backend_cfg->format,
+          backend_idx, platform_get_snd_device_name(snd_device));
+
+   return 0;
+}
+
+
+/*
  *Validate the selected bit_width, sample_rate and channels using the edid
  *of the connected sink device.
  */
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index dfe39a3..61ef223 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -5439,6 +5439,32 @@
 }
 
 /*
+ * Get the backend configuration for current snd device
+ */
+int platform_get_codec_backend_cfg(struct audio_device* adev,
+                         snd_device_t snd_device,
+                         struct audio_backend_cfg *backend_cfg)
+{
+    int backend_idx = platform_get_backend_index(snd_device);
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
+
+    backend_cfg->bit_width = my_data->current_backend_cfg[backend_idx].bit_width;
+    backend_cfg->sample_rate =
+                       my_data->current_backend_cfg[backend_idx].sample_rate;
+    backend_cfg->channels =
+                       my_data->current_backend_cfg[backend_idx].channels;
+    backend_cfg->format =
+                       my_data->current_backend_cfg[backend_idx].format;
+
+    ALOGV("%s:becf: afe: bitwidth %d, samplerate %d channels %d format %d"
+          ", backend_idx %d device (%s)", __func__,  backend_cfg->bit_width,
+          backend_cfg->sample_rate, backend_cfg->channels, backend_cfg->format,
+          backend_idx, platform_get_snd_device_name(snd_device));
+
+   return 0;
+}
+
+/*
  *Validate the selected bit_width, sample_rate and channels using the edid
  *of the connected sink device.
  */