Merge "pal: add stereo-channel volume setting"
diff --git a/session/inc/PayloadBuilder.h b/session/inc/PayloadBuilder.h
index 183e8df..0228668 100644
--- a/session/inc/PayloadBuilder.h
+++ b/session/inc/PayloadBuilder.h
@@ -200,6 +200,9 @@
     void payloadVolumeConfig(uint8_t** payload, size_t* size,
                            uint32_t miid,
                            struct pal_volume_data * data);
+    void payloadMultichVolumemConfig(uint8_t** payload, size_t* size,
+                           uint32_t miid,
+                           struct pal_volume_data * data);
     int payloadCustomParam(uint8_t **alsaPayload, size_t *size,
                             uint32_t *customayload, uint32_t customPayloadSize,
                             uint32_t moduleInstanceId, uint32_t dspParamId);
diff --git a/session/src/PayloadBuilder.cpp b/session/src/PayloadBuilder.cpp
index f23578e..4a07e3f 100644
--- a/session/src/PayloadBuilder.cpp
+++ b/session/src/PayloadBuilder.cpp
@@ -441,8 +441,14 @@
     uint8_t* payloadInfo = NULL;
     size_t payloadSize = 0, padBytes = 0;
 
-    PAL_VERBOSE(LOG_TAG,"volume sent:%f \n",(voldata->volume_pair[0].vol));
-    voldB = (voldata->volume_pair[0].vol);
+    if (voldata->no_of_volpair == 1) {
+        voldB = (voldata->volume_pair[0].vol);
+    } else {
+        voldB = (voldata->volume_pair[0].vol + voldata->volume_pair[1].vol)/2;
+        PAL_DBG(LOG_TAG,"volume sent left:%f , right: %f \n",(voldata->volume_pair[0].vol),
+                  (voldata->volume_pair[1].vol));
+    }
+    PAL_VERBOSE(LOG_TAG,"volume sent:%f \n",voldB);
     vol = (long)(voldB * (PLAYBACK_VOLUME_MAX*1.0));
     payloadSize = sizeof(struct apm_module_param_data_t) +
                   sizeof(struct volume_ctrl_master_gain_t);
@@ -467,6 +473,51 @@
     PAL_DBG(LOG_TAG, "payload %pK size %zu", *payload, *size);
 }
 
+void PayloadBuilder::payloadMultichVolumemConfig(uint8_t** payload, size_t* size,
+        uint32_t miid, struct pal_volume_data* voldata)
+{
+     const uint32_t PLAYBACK_MULTI_VOLUME_GAIN = 1 << 28;
+     struct apm_module_param_data_t* header = nullptr;
+     volume_ctrl_multichannel_gain_t *volConf = nullptr;
+     int numChannels;
+     uint8_t* payloadInfo = NULL;
+     size_t payloadSize = 0, padBytes = 0;
+
+     numChannels = voldata->no_of_volpair;
+     payloadSize = sizeof(struct apm_module_param_data_t) +
+                   sizeof(struct volume_ctrl_multichannel_gain_t) +
+                   numChannels * sizeof(volume_ctrl_channels_gain_config_t);
+     padBytes = PAL_PADDING_8BYTE_ALIGN(payloadSize);
+     payloadInfo = (uint8_t*) calloc(1, payloadSize + padBytes);
+     if (!payloadInfo) {
+         PAL_ERR(LOG_TAG, "payloadInfo malloc failed %s", strerror(errno));
+         return;
+     }
+     header = (struct apm_module_param_data_t*)payloadInfo;
+     header->module_instance_id = miid;
+     header->param_id = PARAM_ID_VOL_CTRL_MULTICHANNEL_GAIN;
+     header->error_code = 0x0;
+     header->param_size = payloadSize -  sizeof(struct apm_module_param_data_t);
+     volConf = (volume_ctrl_multichannel_gain_t *) (payloadInfo + sizeof(struct apm_module_param_data_t));
+     volConf->num_config = numChannels;
+     PAL_DBG(LOG_TAG, "num_config %d", numChannels);
+     /*
+      * Only L/R channel setting is supported. No need to convert channel_mask to channel_map.
+      * If other channel types support, the conversion is needed.
+      */
+     for (uint32_t i = 0; i < numChannels; i++) {
+          volConf->gain_data[i].channel_mask_lsb = (1 << voldata->volume_pair[i].channel_mask);
+          volConf->gain_data[i].channel_mask_msb = 0;
+          volConf->gain_data[i].gain = (uint32_t)((voldata->volume_pair[i].vol) * (PLAYBACK_MULTI_VOLUME_GAIN * 1.0));
+     }
+     PAL_DBG(LOG_TAG, "header params IID:%x param_id:%x error_code:%d param_size:%d",
+                   header->module_instance_id, header->param_id,
+                   header->error_code, header->param_size);
+     *size = payloadSize + padBytes;
+     *payload = payloadInfo;
+     PAL_DBG(LOG_TAG, "payload %pK size %zu", *payload, *size);
+}
+
 void PayloadBuilder::payloadVolumeCtrlRamp(uint8_t** payload, size_t* size,
         uint32_t miid, uint32_t ramp_period_ms)
 {
@@ -3182,6 +3233,7 @@
     }
 
     long voldB = 0;
+    float vol = 0;
     struct pal_volume_data *voldata = NULL;
     voldata = (struct pal_volume_data *)calloc(1, (sizeof(uint32_t) +
                       (sizeof(struct pal_channel_vol_kv) * (0xFFFF))));
@@ -3196,9 +3248,17 @@
         goto error_1;
     }
 
-    PAL_VERBOSE(LOG_TAG,"volume sent:%f \n",(voldata->volume_pair[0].vol));
+    if (voldata->no_of_volpair == 1) {
+        vol = (voldata->volume_pair[0].vol);
+    } else {
+        vol = (voldata->volume_pair[0].vol + voldata->volume_pair[1].vol)/2;
+        PAL_VERBOSE(LOG_TAG,"volume sent left:%f , right: %f \n",(voldata->volume_pair[0].vol),
+                  (voldata->volume_pair[1].vol));
+    }
+
     /*scaling the volume by PLAYBACK_VOLUME_MAX factor*/
-    voldB = (long)((voldata->volume_pair[0].vol) * (PLAYBACK_VOLUME_MAX*1.0));
+    voldB = (long)(vol * (PLAYBACK_VOLUME_MAX*1.0));
+    PAL_VERBOSE(LOG_TAG,"volume sent:%f \n",voldB);
 
     switch (static_cast<uint32_t>(tag)) {
     case TAG_STREAM_VOLUME:
diff --git a/session/src/SessionAlsaCompress.cpp b/session/src/SessionAlsaCompress.cpp
index eac0cb3..e6b9e9e 100644
--- a/session/src/SessionAlsaCompress.cpp
+++ b/session/src/SessionAlsaCompress.cpp
@@ -2182,7 +2182,12 @@
                 goto exit;
             }
 
-            builder->payloadVolumeConfig(&alsaParamData, &alsaPayloadSize, miid, vdata);
+            if (vdata->no_of_volpair == 2 && sAttr.out_media_config.ch_info.channels == 2) {
+                builder->payloadMultichVolumemConfig(&alsaParamData, &alsaPayloadSize, miid, vdata);
+            } else {
+                builder->payloadVolumeConfig(&alsaParamData, &alsaPayloadSize, miid, vdata);
+            }
+
             if (alsaPayloadSize) {
                 status = SessionAlsaUtils::setMixerParameter(mixer, device,
                                                alsaParamData, alsaPayloadSize);