Merge "audio: Fix to return proper channel index masks supported for USB"
diff --git a/configs/msmsteppe/mixer_paths_wcd9375.xml b/configs/msmsteppe/mixer_paths_wcd9375.xml
index 85de3eb..680f445 100644
--- a/configs/msmsteppe/mixer_paths_wcd9375.xml
+++ b/configs/msmsteppe/mixer_paths_wcd9375.xml
@@ -371,8 +371,9 @@
     <ctl name="COMP7 Switch" value="0" />
     <ctl name="COMP8 Switch" value="0" />
 
-    <!-- Headphone Default mode - AB -->
-    <ctl name="RX HPH Mode" value="CLS_AB" />
+    <!-- Headphone class-H mode -->
+    <ctl name="RX_HPH_PWR_MODE" value="ULP" />
+    <ctl name="RX HPH Mode" value="CLS_H_ULP" />
 
     <!-- IIR/voice anc -->
     <ctl name="IIR0 Band1" id ="0" value="268435456" />
@@ -2130,9 +2131,13 @@
     </path>
 
     <path name="hph-highquality-mode">
+        <ctl name="RX_HPH_PWR_MODE" value="LOHIFI" />
+        <ctl name="RX HPH Mode" value="CLS_H_LOHIFI" />
     </path>
 
     <path name="hph-lowpower-mode">
+        <ctl name="RX_HPH_PWR_MODE" value="ULP" />
+        <ctl name="RX HPH Mode" value="CLS_H_ULP" />
     </path>
 
     <path name="true-native-mode">
diff --git a/configs/msmsteppe/mixer_paths_wcd9375qrd.xml b/configs/msmsteppe/mixer_paths_wcd9375qrd.xml
index df6890b..2a9499e 100644
--- a/configs/msmsteppe/mixer_paths_wcd9375qrd.xml
+++ b/configs/msmsteppe/mixer_paths_wcd9375qrd.xml
@@ -371,8 +371,9 @@
     <ctl name="COMP7 Switch" value="0" />
     <ctl name="COMP8 Switch" value="0" />
 
-    <!-- Headphone Default mode - AB -->
-    <ctl name="RX HPH Mode" value="CLS_AB" />
+    <!-- Headphone class-H mode  -->
+    <ctl name="RX_HPH_PWR_MODE" value="ULP" />
+    <ctl name="RX HPH Mode" value="CLS_H_ULP" />
 
     <!-- IIR/voice anc -->
     <ctl name="IIR0 Band1" id ="0" value="268435456" />
@@ -2210,9 +2211,13 @@
     </path>
 
     <path name="hph-highquality-mode">
+        <ctl name="RX_HPH_PWR_MODE" value="LOHIFI" />
+        <ctl name="RX HPH Mode" value="CLS_H_LOHIFI" />
     </path>
 
     <path name="hph-lowpower-mode">
+        <ctl name="RX_HPH_PWR_MODE" value="ULP" />
+        <ctl name="RX HPH Mode" value="CLS_H_ULP" />
     </path>
 
     <path name="true-native-mode">
diff --git a/configs/sdm710/audio_platform_info_intcodec.xml b/configs/sdm710/audio_platform_info_intcodec.xml
index 603ec57..4ae3bb1 100644
--- a/configs/sdm710/audio_platform_info_intcodec.xml
+++ b/configs/sdm710/audio_platform_info_intcodec.xml
@@ -27,6 +27,8 @@
 <audio_platform_info>
     <bit_width_configs>
         <device name="SND_DEVICE_OUT_SPEAKER" bit_width="24"/>
+        <device name="SND_DEVICE_IN_HANDSET_MIC" bit_width="24"/>
+        <device name="SND_DEVICE_IN_HANDSET_GENERIC_QMIC" bit_width="24"/>
     </bit_width_configs>
     <interface_names>
         <device name="AUDIO_DEVICE_IN_BUILTIN_MIC" interface="INT3_MI2S" codec_type="internal"/>
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index ba096c9..ae1fef7 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -64,6 +64,8 @@
 
 #define MAX_SLEEP_RETRY 100
 #define WIFI_INIT_WAIT_SLEEP 50
+#define MAX_NUM_CHANNELS 8
+#define Q14_GAIN_UNITY 0x4000
 
 struct audio_extn_module {
     bool anc_enabled;
@@ -301,6 +303,74 @@
         ALOGV("%s: Setting custom stereo state success", __func__);
     }
 }
+
+void audio_extn_send_dual_mono_mixing_coefficients(struct stream_out *out)
+{
+    struct audio_device *adev = out->dev;
+    struct mixer_ctl *ctl;
+    char mixer_ctl_name[128];
+    int cust_ch_mixer_cfg[128], len = 0;
+    int ip_channel_cnt = audio_channel_count_from_out_mask(out->channel_mask);
+    int pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
+    int op_channel_cnt = 2;
+    int i, j, err;
+
+    ALOGV("%s", __func__);
+    if (!out->started) {
+        out->set_dual_mono = true;
+        goto exit;
+    }
+
+    ALOGD("%s: i/p channel count %d, o/p channel count %d, pcm id %d", __func__,
+           ip_channel_cnt, op_channel_cnt, pcm_device_id);
+
+    snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+             "Audio Stream %d Channel Mix Cfg", pcm_device_id);
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: ERROR. Could not get ctl for mixer cmd - %s",
+        __func__, mixer_ctl_name);
+        goto exit;
+    }
+
+    /* Output channel count corresponds to backend configuration channels.
+     * Input channel count corresponds to ASM session channels.
+     * Set params is called with channels that need to be selected from
+     * input to generate output.
+     * ex: "8,2" to downmix from 8 to 2 i.e. to downmix from 8 to 2,
+     *
+     * This mixer control takes values in the following sequence:
+     * - input channel count(m)
+     * - output channel count(n)
+     * - weight coeff for [out ch#1, in ch#1]
+     * ....
+     * - weight coeff for [out ch#1, in ch#m]
+     *
+     * - weight coeff for [out ch#2, in ch#1]
+     * ....
+     * - weight coeff for [out ch#2, in ch#m]
+     *
+     * - weight coeff for [out ch#n, in ch#1]
+     * ....
+     * - weight coeff for [out ch#n, in ch#m]
+     *
+     * To get dualmono ouptu weightage coeff is calculated as Unity gain
+     * divided by number of input channels.
+     */
+    cust_ch_mixer_cfg[len++] = ip_channel_cnt;
+    cust_ch_mixer_cfg[len++] = op_channel_cnt;
+    for (i = 0; i < op_channel_cnt; i++) {
+         for (j = 0; j < ip_channel_cnt; j++) {
+              cust_ch_mixer_cfg[len++] = Q14_GAIN_UNITY/ip_channel_cnt;
+         }
+    }
+
+    err = mixer_ctl_set_array(ctl, cust_ch_mixer_cfg, len);
+    if (err)
+        ALOGE("%s: ERROR. Mixer ctl set failed", __func__);
+exit:
+    return;
+}
 #endif /* CUSTOM_STEREO_ENABLED */
 
 #ifndef DTS_EAGLE
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index e74bd36..b2b0e73 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -43,6 +43,8 @@
 #include "ip_hdlr_intf.h"
 #include "battery_listener.h"
 
+#define AUDIO_PARAMETER_DUAL_MONO  "dual_mono"
+
 #ifndef AFE_PROXY_ENABLED
 #define AUDIO_DEVICE_OUT_PROXY 0x40000
 #endif
@@ -1132,4 +1134,9 @@
 int audio_extn_ext_hw_plugin_set_audio_gain(void *plugin,
             struct audio_usecase *usecase, uint32_t gain);
 #endif
+#ifndef CUSTOM_STEREO_ENABLED
+#define audio_extn_send_dual_mono_mixing_coefficients(out) (0)
+#else
+void audio_extn_send_dual_mono_mixing_coefficients(struct stream_out *out);
+#endif
 #endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/passthru.c b/hal/audio_extn/passthru.c
index b608043..9180391 100644
--- a/hal/audio_extn/passthru.c
+++ b/hal/audio_extn/passthru.c
@@ -546,6 +546,12 @@
                                                    struct stream_out *out)
 {
     struct audio_backend_cfg backend_cfg;
+    backend_cfg.sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    backend_cfg.channels = CODEC_BACKEND_DEFAULT_CHANNELS;
+    backend_cfg.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+    backend_cfg.format = AUDIO_FORMAT_PCM_16_BIT;
+    backend_cfg.passthrough_enabled = false;
+
     snd_device_t out_snd_device = SND_DEVICE_NONE;
     int max_edid_channels = platform_edid_get_max_channels(out->dev->platform);
 
diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c
index fc97cce..59fb5a3 100644
--- a/hal/audio_extn/spkr_protection.c
+++ b/hal/audio_extn/spkr_protection.c
@@ -747,7 +747,7 @@
     struct timespec ts;
     bool acquire_device = false;
 
-    status.status = 0;
+    memset(&status, 0, sizeof(status));
     memset(&protCfg, 0, sizeof(protCfg));
     if (!adev) {
         ALOGE("%s: Invalid params", __func__);
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 2053d3c..5c7fc9c 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -3210,6 +3210,8 @@
             }
             break;
         }
+        platform_set_stream_channel_map(adev->platform, out->channel_mask,
+                   out->pcm_device_id, &out->channel_map_param.channel_map[0]);
 
         ALOGV("%s: pcm_prepare", __func__);
         if (pcm_is_ready(out->pcm)) {
@@ -3223,8 +3225,6 @@
                 goto error_open;
             }
         }
-        platform_set_stream_channel_map(adev->platform, out->channel_mask,
-                   out->pcm_device_id, &out->channel_map_param.channel_map[0]);
         // apply volume for voip playback after path is set up
         if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP)
             out_set_voip_volume(&out->stream, out->volume_l, out->volume_r);
@@ -4020,6 +4020,13 @@
         pthread_mutex_unlock(&out->lock);
     }
 
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_DUAL_MONO, value,
+                            sizeof(value));
+    if (err >= 0) {
+        if (!strncmp("true", value, sizeof("true")) || atoi(value))
+            audio_extn_send_dual_mono_mixing_coefficients(out);
+    }
+
     err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_PROFILE, value, sizeof(value));
     if (err >= 0) {
         strlcpy(out->profile, value, sizeof(out->profile));
@@ -4630,6 +4637,8 @@
             ret = -EINVAL;
             goto exit;
         }
+        if (out->set_dual_mono)
+            audio_extn_send_dual_mono_mixing_coefficients(out);
     }
 
     if (adev->is_channel_status_set == false && (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)){
@@ -6002,6 +6011,7 @@
     out->a2dp_compress_mute = false;
     out->hal_output_suspend_supported = 0;
     out->dynamic_pm_qos_config_supported = 0;
+    out->set_dual_mono = false;
 
     if ((flags & AUDIO_OUTPUT_FLAG_BD) &&
         (property_get_bool("vendor.audio.matrix.limiter.enable", false)))
@@ -7273,6 +7283,7 @@
         in->usecase = USECASE_AUDIO_RECORD_MMAP;
         in->config = pcm_config_mmap_capture;
         in->config.format = pcm_format_from_audio_format(config->format);
+        in->config.channels = channel_count;
         in->stream.start = in_start;
         in->stream.stop = in_stop;
         in->stream.create_mmap_buffer = in_create_mmap_buffer;
@@ -7424,8 +7435,10 @@
     // between the callback and close_stream
     audio_extn_snd_mon_unregister_listener(stream);
 
-    /* Disable echo reference while closing input stream */
-    platform_set_echo_reference(adev, false, AUDIO_DEVICE_NONE);
+    // Disable echo reference if there are no active input and hfp call
+    // while closing input stream
+    if (!adev->active_input && !audio_extn_hfp_is_active(adev))
+        platform_set_echo_reference(adev, false, AUDIO_DEVICE_NONE);
 
     if (in == NULL) {
         ALOGE("%s: audio_stream_in ptr is NULL", __func__);
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index c13ca56..1675893 100755
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -354,6 +354,7 @@
     bool stream_config_changed;
     mix_matrix_params_t pan_scale_params;
     mix_matrix_params_t downmix_params;
+    bool set_dual_mono;
 };
 
 struct stream_in {
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 2539ed1..30b9d10 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -2381,8 +2381,6 @@
             ALOGD("ACDB initialization failed");
         }
     }
-    /* init keep-alive for compress passthru */
-    audio_extn_keep_alive_init(adev);
 #ifdef DYNAMIC_LOG_ENABLED
     log_utils_init();
 #endif
@@ -6473,7 +6471,8 @@
  */
 static bool platform_check_capture_codec_backend_cfg(struct audio_device* adev,
                                    int backend_idx,
-                                   struct audio_backend_cfg *backend_cfg)
+                                   struct audio_backend_cfg *backend_cfg,
+                                   snd_device_t snd_device)
 {
     bool backend_change = false;
     unsigned int bit_width;
@@ -6494,14 +6493,18 @@
     // For voice calls use default configuration i.e. 16b/48K, only applicable to
     // default backend
     // force routing is not required here, caller will do it anyway
-    if ((voice_is_in_call(adev) || adev->mode == AUDIO_MODE_IN_COMMUNICATION)
-        || (my_data->is_internal_codec)) {
+    if ((voice_is_in_call(adev) || adev->mode == AUDIO_MODE_IN_COMMUNICATION)) {
 
         ALOGW("%s:txbecf: afe: Use default bw and sr for voice/voip calls and "
               "for unprocessed/camera source", __func__);
         bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
         sample_rate =  CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
         channels = CODEC_BACKEND_DEFAULT_TX_CHANNELS;
+    } else if (my_data->is_internal_codec && !audio_is_usb_in_device(snd_device)) {
+        sample_rate =  CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+        channels = CODEC_BACKEND_DEFAULT_TX_CHANNELS;
+        if (adev->active_input->bit_width == 24)
+            bit_width = platform_get_snd_device_bit_width(snd_device);
     } else {
         struct listnode *node;
         struct audio_usecase *uc = NULL;
@@ -6593,7 +6596,7 @@
           backend_idx, usecase->id,
           platform_get_snd_device_name(snd_device));
     if (platform_check_capture_codec_backend_cfg(adev, backend_idx,
-                                                 &backend_cfg)) {
+                                                 &backend_cfg, snd_device)) {
         ret = platform_set_codec_backend_cfg(adev, snd_device,
                                              backend_cfg);
         if(!ret)
diff --git a/qahw_api/test/qahw_playback_test.c b/qahw_api/test/qahw_playback_test.c
index 4160754..a048d3e 100644
--- a/qahw_api/test/qahw_playback_test.c
+++ b/qahw_api/test/qahw_playback_test.c
@@ -251,6 +251,7 @@
         stream_param[i].ethread_data                        =   nullptr;
         stream_param[i].device_url                          =   "stream";
         stream_param[i].play_later                          =   false;
+        stream_param[i].set_params                          =   nullptr;
 
         pthread_mutex_init(&stream_param[i].write_lock, (const pthread_mutexattr_t *)NULL);
         pthread_cond_init(&stream_param[i].write_cond, (const pthread_condattr_t *) NULL);
@@ -797,6 +798,14 @@
     if (bytes_to_read <= 0)
         read_complete_file = true;
 
+    if (params->set_params) {
+        rc = qahw_out_set_parameters(params->out_handle, params->set_params);
+        if (rc) {
+            fprintf(log_file, "stream %s: failed to set kvpairs\n", params->set_params);
+            fprintf(stderr, "stream %s: failed to set kvpairs\n", params->set_params);
+        }
+    }
+
     while (!exit && !stop_playback) {
         if (!bytes_remaining) {
             fprintf(log_file, "\nstream %d: reading bytes %zd\n", params->stream_index, bytes_wanted);
@@ -2095,7 +2104,7 @@
 
     while ((opt = getopt_long(argc,
                               argv,
-                              "-f:r:c:b:d:s:v:V:l:t:a:w:k:PD:KF:Ee:A:u:m:S:C:p::x:y:qQh:i:h:g:",
+                              "-f:r:c:b:d:s:v:V:l:t:a:w:k:PD:KF:Ee:A:u:m:S:C:p::x:y:qQh:i:h:g:O:",
                               long_options,
                               &option_index)) != -1) {
 
@@ -2233,6 +2242,9 @@
         case 'K':
             kpi_mode = true;
             break;
+        case 'O':
+            stream_param[i].set_params = optarg;
+            break;
         case 'F':
             stream_param[i].flags = atoll(optarg);
             stream_param[i].flags_set = true;
@@ -2533,6 +2545,7 @@
         fprintf(log_file, "stream %d: Bitwidth:%d\n", stream->stream_index, stream->config.offload_info.bit_width);
         fprintf(log_file, "stream %d: AAC Format Type:%d\n", stream->stream_index, stream->aac_fmt_type);
         fprintf(log_file, "stream %d: Kvpair Values:%s\n", stream->stream_index, stream->kvpair_values);
+        fprintf(log_file, "stream %d: set params Values:%s\n", stream->stream_index, stream->set_params);
         fprintf(log_file, "Log file:%s\n", log_filename);
         fprintf(log_file, "Volume level:%f\n", vol_level);
 
diff --git a/qahw_api/test/qahw_playback_test.h b/qahw_api/test/qahw_playback_test.h
index 66229f5..b8bddbc 100644
--- a/qahw_api/test/qahw_playback_test.h
+++ b/qahw_api/test/qahw_playback_test.h
@@ -143,6 +143,7 @@
     pthread_cond_t input_buffer_available_cond;
     pthread_mutex_t input_buffer_available_lock;
     uint32_t input_buffer_available_size;
+    char *set_params;
 }stream_config;
 
 qahw_module_handle_t * load_hal(audio_devices_t dev);