Merge "hal: Audiosphere SA+ concurrency implementation"
diff --git a/hal/audio_extn/audio_defs.h b/hal/audio_extn/audio_defs.h
index 96b0a8b..9d80112 100644
--- a/hal/audio_extn/audio_defs.h
+++ b/hal/audio_extn/audio_defs.h
@@ -72,6 +72,8 @@
 #define AUDIO_OFFLOAD_CODEC_APE_SAMPLE_RATE "music_offload_ape_sample_rate"
 #define AUDIO_OFFLOAD_CODEC_APE_SEEK_TABLE_PRESENT "music_offload_seek_table_present"
 
+#define AUDIO_OFFLOAD_CODEC_VORBIS_BITSTREAM_FMT "music_offload_vorbis_bitstream_fmt"
+
 /* Query handle fm parameter*/
 #define AUDIO_PARAMETER_KEY_HANDLE_FM "handle_fm"
 
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 061af81..39ad4d1 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -608,25 +608,23 @@
     if (out->format == AUDIO_FORMAT_FLAC) {
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MIN_BLK_SIZE, value, sizeof(value));
         if (ret >= 0) {
-            out->gapless_mdata.min_blk_size =
             out->compr_config.codec->options.flac_dec.min_blk_size = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MAX_BLK_SIZE, value, sizeof(value));
         if (ret >= 0) {
-            out->gapless_mdata.max_blk_size =
             out->compr_config.codec->options.flac_dec.max_blk_size = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MIN_FRAME_SIZE, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.flac_dec.min_frame_size = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MAX_FRAME_SIZE, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.flac_dec.max_frame_size = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ALOGV("FLAC metadata: min_blk_size %d, max_blk_size %d min_frame_size %d max_frame_size %d",
               out->compr_config.codec->options.flac_dec.min_blk_size,
@@ -639,63 +637,63 @@
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_FRAME_LENGTH, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.frame_length = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_COMPATIBLE_VERSION, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.compatible_version = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_BIT_DEPTH, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.bit_depth = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_PB, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.pb = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_MB, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.mb = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
 
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_KB, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.kb = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_NUM_CHANNELS, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.num_channels = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_MAX_RUN, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.max_run = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_MAX_FRAME_BYTES, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.max_frame_bytes = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_AVG_BIT_RATE, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.avg_bit_rate = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_SAMPLING_RATE, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.sample_rate = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_CHANNEL_LAYOUT_TAG, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.channel_layout_tag = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ALOGV("ALAC CSD values: frameLength %d bitDepth %d numChannels %d"
                 " maxFrameBytes %d, avgBitRate %d, sampleRate %d",
@@ -711,52 +709,52 @@
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_COMPATIBLE_VERSION, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.ape.compatible_version = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_COMPRESSION_LEVEL, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.ape.compression_level = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_FORMAT_FLAGS, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.ape.format_flags = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_BLOCKS_PER_FRAME, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.ape.blocks_per_frame = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_FINAL_FRAME_BLOCKS, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.ape.final_frame_blocks = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_TOTAL_FRAMES, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.ape.total_frames = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_BITS_PER_SAMPLE, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.ape.bits_per_sample = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_NUM_CHANNELS, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.ape.num_channels = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_SAMPLE_RATE, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.ape.sample_rate = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_SEEK_TABLE_PRESENT, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.ape.seek_table_present = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ALOGV("APE CSD values: compatibleVersion %d compressionLevel %d"
                 " formatFlags %d blocksPerFrame %d finalFrameBlocks %d"
@@ -775,49 +773,59 @@
     }
 
     else if (out->format == AUDIO_FORMAT_VORBIS) {
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_VORBIS_BITSTREAM_FMT, value, sizeof(value));
+        if (ret >= 0) {
         // transcoded bitstream mode
-        out->compr_config.codec->options.vorbis_dec.bit_stream_fmt = 1;
-        out->send_new_metadata = 1;
+            out->compr_config.codec->options.vorbis_dec.bit_stream_fmt = (atoi(value) > 0) ? 1 : 0;
+            out->is_compr_metadata_avail = true;
+        }
     }
 
     else if (out->format == AUDIO_FORMAT_WMA || out->format == AUDIO_FORMAT_WMA_PRO) {
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_FORMAT_TAG, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->format = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_AVG_BIT_RATE, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.wma.avg_bit_rate = atoi(value);
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_BLOCK_ALIGN, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.wma.super_block_align = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_BIT_PER_SAMPLE, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.wma.bits_per_sample = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_CHANNEL_MASK, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.wma.channelmask = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.wma.encodeopt = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION1, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.wma.encodeopt1 = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION2, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.wma.encodeopt2 = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
-        ALOGV("WMA params: fmt %x, balgn %x, sr %d, chmsk %x, encop %x, op1 %x, op2 %x",
+        ALOGV("WMA params: fmt %x, bit rate %x, balgn %x, sr %d, chmsk %x"
+                " encop %x, op1 %x, op2 %x",
                 out->compr_config.codec->format,
+                out->compr_config.codec->options.wma.avg_bit_rate,
                 out->compr_config.codec->options.wma.super_block_align,
                 out->compr_config.codec->options.wma.bits_per_sample,
                 out->compr_config.codec->options.wma.channelmask,
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index ab3e373..a0dd5ae 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -450,7 +450,8 @@
                                   uint32_t sample_rate,
                                   uint32_t bit_width,
                                   struct stream_app_type_cfg *app_type_cfg);
-int audio_extn_utils_send_app_type_cfg(struct audio_usecase *usecase);
+int audio_extn_utils_send_app_type_cfg(struct audio_device *adev,
+                                       struct audio_usecase *usecase);
 void audio_extn_utils_send_audio_calibration(struct audio_device *adev,
                                              struct audio_usecase *usecase);
 #ifdef DS2_DOLBY_DAP_ENABLED
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index 24dee64..b9e2a40 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -504,14 +504,11 @@
     app_type_cfg->bit_width = 16;
 }
 
-#define GENERAL_RECORDING_APP_TYPE  0x11132
-int audio_extn_utils_send_app_type_cfg(struct audio_usecase *usecase)
+int audio_extn_utils_send_app_type_cfg(struct audio_device *adev,
+                                       struct audio_usecase *usecase)
 {
     char mixer_ctl_name[MAX_LENGTH_MIXER_CONTROL_IN_INT];
     int app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT], len = 0, rc;
-    struct stream_out *out;
-    struct stream_in *in;
-    struct audio_device *adev;
     struct mixer_ctl *ctl;
     int pcm_device_id, acdb_dev_id, snd_device = usecase->out_snd_device;
     int32_t sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
@@ -528,21 +525,16 @@
         (usecase->id != USECASE_AUDIO_PLAYBACK_MULTI_CH) &&
         (!is_offload_usecase(usecase->id)) &&
         (usecase->type != PCM_CAPTURE)) {
-        ALOGV("%s: a playback path where app type cfg is not required %d", __func__, usecase->id);
+        ALOGV("%s: a rx/tx path where app type cfg is not required %d", __func__, usecase->id);
         rc = 0;
         goto exit_send_app_type_cfg;
     }
     if (usecase->type == PCM_PLAYBACK) {
-        out = usecase->stream.out;
-        adev = out->dev;
         snd_device = usecase->out_snd_device;
-        pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
-    }
-    if (usecase->type == PCM_CAPTURE) {
-        in = usecase->stream.in;
-        adev = in->dev;
+        pcm_device_id = platform_get_pcm_device_id(usecase->id, PCM_PLAYBACK);
+    } else if (usecase->type == PCM_CAPTURE) {
         snd_device = usecase->in_snd_device;
-        pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE);
+        pcm_device_id = platform_get_pcm_device_id(usecase->id, PCM_CAPTURE);
     }
 
     snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
@@ -564,7 +556,14 @@
         goto exit_send_app_type_cfg;
     }
 
-    if (usecase->type == PCM_PLAYBACK) {
+    if ((usecase->type == PCM_PLAYBACK) && (usecase->stream.out == NULL)) {
+        sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
+        app_type_cfg[len++] = platform_get_default_app_type(adev->platform);
+        app_type_cfg[len++] = acdb_dev_id;
+        app_type_cfg[len++] = sample_rate;
+        ALOGI("%s PLAYBACK app_type %d, acdb_dev_id %d, sample_rate %d",
+              __func__, platform_get_default_app_type(adev->platform), acdb_dev_id, sample_rate);
+    } else if (usecase->type == PCM_PLAYBACK) {
         if ((24 == usecase->stream.out->bit_width) &&
             (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER)) {
             sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
@@ -573,13 +572,13 @@
             (usecase->stream.out->sample_rate < OUTPUT_SAMPLING_RATE_44100)) {
             sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
         } else {
-            sample_rate = out->app_type_cfg.sample_rate;
+            sample_rate = usecase->stream.out->app_type_cfg.sample_rate;
         }
 
-        app_type_cfg[len++] = out->app_type_cfg.app_type;
+        app_type_cfg[len++] = usecase->stream.out->app_type_cfg.app_type;
         app_type_cfg[len++] = acdb_dev_id;
-        if (((out->format == AUDIO_FORMAT_E_AC3) ||
-            (out->format == AUDIO_FORMAT_E_AC3_JOC))
+        if (((usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
+            (usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC))
 #ifdef HDMI_PASSTHROUGH_ENABLED
             && (out->flags  & AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH)
 #endif
@@ -588,10 +587,9 @@
         else
             app_type_cfg[len++] = sample_rate;
         ALOGI("%s PLAYBACK app_type %d, acdb_dev_id %d, sample_rate %d",
-              __func__, out->app_type_cfg.app_type, acdb_dev_id, sample_rate);
-    }
-    else if (usecase->type == PCM_CAPTURE) {
-        app_type_cfg[len++] = GENERAL_RECORDING_APP_TYPE;
+              __func__, usecase->stream.out->app_type_cfg.app_type, acdb_dev_id, sample_rate);
+    } else if (usecase->type == PCM_CAPTURE) {
+        app_type_cfg[len++] = platform_get_default_app_type(adev->platform);
         app_type_cfg[len++] = acdb_dev_id;
         app_type_cfg[len++] = sample_rate;
         ALOGI("%s CAPTURE app_type %d, acdb_dev_id %d, sample_rate %d",
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index e35f26d..acf1e38 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -454,7 +454,7 @@
     audio_extn_sound_trigger_update_stream_status(usecase, ST_EVENT_STREAM_BUSY);
     audio_extn_listen_update_stream_status(usecase, LISTEN_EVENT_STREAM_BUSY);
     audio_extn_utils_send_audio_calibration(adev, usecase);
-    audio_extn_utils_send_app_type_cfg(usecase);
+    audio_extn_utils_send_app_type_cfg(adev, usecase);
     strcpy(mixer_path, use_case_table[usecase->id]);
     platform_add_backend_name(mixer_path, snd_device, usecase);
     ALOGV("%s: apply mixer and update path: %s", __func__, mixer_path);
@@ -1326,6 +1326,10 @@
                 ALOGE("%s: Next track returned error %d",__func__, ret);
             if (ret != -ENETRESET) {
                 send_callback = true;
+                pthread_mutex_lock(&out->lock);
+                out->send_new_metadata = 1;
+                out->send_next_track_params = true;
+                pthread_mutex_unlock(&out->lock);
                 event = STREAM_CBK_EVENT_DRAIN_READY;
                 ALOGV("copl(%p):send drain callback, ret %d", out, ret);
             } else
@@ -1655,6 +1659,9 @@
             ret = -EIO;
             goto error_open;
         }
+        /* compress_open sends params of the track, so reset the flag here */
+        out->is_compr_metadata_avail = false;
+
         if (out->offload_callback)
             compress_nonblock(out->compr, out->non_blocking);
 
@@ -1834,6 +1841,8 @@
         } else {
             ALOGD("copl(%p):standby", out);
             stop_compressed_output_l(out);
+            out->send_next_track_params = false;
+            out->is_compr_metadata_avail = false;
             out->gapless_mdata.encoder_delay = 0;
             out->gapless_mdata.encoder_padding = 0;
             if (out->compr != NULL) {
@@ -1859,7 +1868,6 @@
 {
     int ret = 0;
     char value[32];
-    bool is_meta_data_params = false;
 
     if (!out || !parms) {
         ALOGE("%s: return invalid ",__func__);
@@ -1868,31 +1876,15 @@
 
     ret = audio_extn_parse_compress_metadata(out, parms);
 
-    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_SAMPLE_RATE, value, sizeof(value));
-    if(ret >= 0)
-        is_meta_data_params = true;
-    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_NUM_CHANNEL, value, sizeof(value));
-    if(ret >= 0)
-        is_meta_data_params = true;
-    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_AVG_BIT_RATE, value, sizeof(value));
-    if(ret >= 0)
-        is_meta_data_params = true;
     ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, value, sizeof(value));
     if (ret >= 0) {
-        is_meta_data_params = true;
         out->gapless_mdata.encoder_delay = atoi(value); //whats a good limit check?
     }
     ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, value, sizeof(value));
     if (ret >= 0) {
-        is_meta_data_params = true;
         out->gapless_mdata.encoder_padding = atoi(value);
     }
 
-    if(!is_meta_data_params) {
-        ALOGV("%s: Not gapless meta data params", __func__);
-        return 0;
-    }
-    out->send_new_metadata = 1;
     ALOGV("%s new encoder delay %u and padding %u", __func__,
           out->gapless_mdata.encoder_delay, out->gapless_mdata.encoder_padding);
 
@@ -2186,6 +2178,12 @@
             ALOGD("copl(%p):send new gapless metadata", out);
             compress_set_gapless_metadata(out->compr, &out->gapless_mdata);
             out->send_new_metadata = 0;
+            if (out->send_next_track_params && out->is_compr_metadata_avail) {
+                ALOGD("copl(%p):send next track params in gapless", out);
+                compress_set_next_track_param(out->compr, &(out->compr_config.codec->options));
+                out->send_next_track_params = false;
+                out->is_compr_metadata_avail = false;
+            }
         }
 
         ret = compress_write(out->compr, buffer, bytes);
@@ -3015,6 +3013,8 @@
         }
 
         out->send_new_metadata = 1;
+        out->send_next_track_params = false;
+        out->is_compr_metadata_avail = false;
         out->offload_state = OFFLOAD_STATE_IDLE;
         out->playback_started = 0;
 
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 4b9bce8..5c1ea1d 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -218,6 +218,8 @@
     void *offload_cookie;
     struct compr_gapless_mdata gapless_mdata;
     int send_new_metadata;
+    bool send_next_track_params;
+    bool is_compr_metadata_avail;
     unsigned int bit_width;
 
     struct audio_device *dev;
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index aaca0b2..baec1e0 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -236,11 +236,17 @@
 
 static bool is_external_codec = false;
 static const int pcm_device_table_of_ext_codec[AUDIO_USECASE_MAX][2] = {
-   [USECASE_QCHAT_CALL] = {QCHAT_CALL_PCM_DEVICE_OF_EXT_CODEC, QCHAT_CALL_PCM_DEVICE_OF_EXT_CODEC}
+   [USECASE_QCHAT_CALL] = {QCHAT_CALL_PCM_DEVICE_OF_EXT_CODEC, QCHAT_CALL_PCM_DEVICE_OF_EXT_CODEC},
+   [USECASE_VOICEMMODE1_CALL] = {VOICEMMODE1_CALL_PCM_DEVICE_OF_EXT_CODEC,
+                                 VOICEMMODE1_CALL_PCM_DEVICE_OF_EXT_CODEC},
+   [USECASE_VOICEMMODE2_CALL] = {VOICEMMODE2_CALL_PCM_DEVICE_OF_EXT_CODEC,
+                                 VOICEMMODE2_CALL_PCM_DEVICE_OF_EXT_CODEC},
 };
 
 /* List of use cases that has different PCM device ID's for internal and external codecs */
-static const int misc_usecase[AUDIO_USECASE_MAX] = { USECASE_QCHAT_CALL };
+static const int misc_usecase[AUDIO_USECASE_MAX] = {USECASE_QCHAT_CALL,
+                                                    USECASE_VOICEMMODE1_CALL,
+                                                    USECASE_VOICEMMODE2_CALL};
 
 int pcm_device_table[AUDIO_USECASE_MAX][2] = {
     [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {DEEP_BUFFER_PCM_DEVICE,
@@ -281,6 +287,10 @@
     [USECASE_VOLTE_CALL] = {VOLTE_CALL_PCM_DEVICE, VOLTE_CALL_PCM_DEVICE},
     [USECASE_QCHAT_CALL] = {QCHAT_CALL_PCM_DEVICE, QCHAT_CALL_PCM_DEVICE},
     [USECASE_VOWLAN_CALL] = {VOWLAN_CALL_PCM_DEVICE, VOWLAN_CALL_PCM_DEVICE},
+    [USECASE_VOICEMMODE1_CALL] = {VOICEMMODE1_CALL_PCM_DEVICE,
+                                  VOICEMMODE1_CALL_PCM_DEVICE},
+    [USECASE_VOICEMMODE2_CALL] = {VOICEMMODE2_CALL_PCM_DEVICE,
+                                  VOICEMMODE2_CALL_PCM_DEVICE},
     [USECASE_COMPRESS_VOIP_CALL] = {COMPRESS_VOIP_CALL_PCM_DEVICE, COMPRESS_VOIP_CALL_PCM_DEVICE},
     [USECASE_INCALL_REC_UPLINK] = {AUDIO_RECORD_PCM_DEVICE,
                                    AUDIO_RECORD_PCM_DEVICE},
@@ -656,6 +666,8 @@
     {TO_NAME_INDEX(USECASE_VOLTE_CALL)},
     {TO_NAME_INDEX(USECASE_QCHAT_CALL)},
     {TO_NAME_INDEX(USECASE_VOWLAN_CALL)},
+    {TO_NAME_INDEX(USECASE_VOICEMMODE1_CALL)},
+    {TO_NAME_INDEX(USECASE_VOICEMMODE2_CALL)},
     {TO_NAME_INDEX(USECASE_INCALL_REC_UPLINK)},
     {TO_NAME_INDEX(USECASE_INCALL_REC_DOWNLINK)},
     {TO_NAME_INDEX(USECASE_INCALL_REC_UPLINK_AND_DOWNLINK)},
@@ -742,7 +754,7 @@
      if (!strncmp(snd_card_name, "msm8939-tapan-snd-card",
                   sizeof("msm8939-tapan-snd-card")) ||
          !strncmp(snd_card_name, "msm8939-tapan9302-snd-card",
-                  sizeof("msm8939-tapan9302-snd-card"))||
+                  sizeof("msm8939-tapan9302-snd-card")) ||
          !strncmp(snd_card_name, "msm8939-tomtom9330-snd-card",
                   sizeof("msm8939-tomtom9330-snd-card")) ||
          !strncmp(snd_card_name, "msm8952-tomtom-snd-card",
@@ -873,7 +885,7 @@
         msm_be_id_array_len  =
             sizeof(msm_device_to_be_id_external_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
     } else if (!strncmp(snd_card_name, "msm8952-snd-card-mtp",
-                 sizeof("msm8952-snd-card-mtpmsm8952-snd-card-mtp"))) {
+                 sizeof("msm8952-snd-card-mtp"))) {
         strlcpy(mixer_xml_path, MIXER_XML_PATH_MTP,
                 sizeof(MIXER_XML_PATH_MTP));
         msm_device_to_be_id = msm_device_to_be_id_internal_codec;
@@ -1625,6 +1637,26 @@
     my_data->current_backend_cfg[HEADPHONE_44_1_BACKEND].samplerate_mixer_ctl =
         strdup("SLIM_5_RX SampleRate");
 
+
+    if (platform_get_native_support()) {
+
+        if (!strncmp(snd_card_name, "msm8976-tasha-snd-card",
+            sizeof("msm8976-tasha-snd-card")) ||
+            !strncmp(snd_card_name, "msm8976-tashalite-snd-card",
+            sizeof("msm8976-tashalite-snd-card"))) {
+            /* do nothing */
+        }
+        else {
+            platform_set_native_support(false);
+        }
+    }
+
+    ALOGD("native: native audio: %s for sound card %s",
+        (platform_get_native_support() ? "enabled" : "disabled"),
+        snd_card_name);
+
+
+
     my_data->edid_info = NULL;
     return my_data;
 }
@@ -1914,7 +1946,7 @@
 {
     na_props.platform_na_prop_enabled = na_props.ui_na_prop_enabled
         = codec_support;
-    ALOGD("%s: na_props.platform_na_prop_enabled: %d", __func__,
+    ALOGV("%s: na_props.platform_na_prop_enabled: %d", __func__,
            na_props.platform_na_prop_enabled);
     return 0;
 }
@@ -3502,6 +3534,8 @@
     *  USECASE_VOLTE_CALL:
     *  USECASE_QCHAT_CALL:
     *  USECASE_VOWLAN_CALL:
+    *  USECASE_VOICEMMODE1_CALL:
+    *  USECASE_VOICEMMODE2_CALL:
     *  USECASE_COMPRESS_VOIP_CALL:
     *  USECASE_AUDIO_RECORD_FM_VIRTUAL:
     *  USECASE_INCALL_REC_UPLINK:
@@ -3564,6 +3598,8 @@
     *  USECASE_VOLTE_CALL:
     *  USECASE_QCHAT_CALL:
     *  USECASE_VOWLAN_CALL:
+    *  USECASE_VOICEMMODE1_CALL:
+    *  USECASE_VOICEMMODE2_CALL:
     *  USECASE_COMPRESS_VOIP_CALL:
     *  USECASE_AUDIO_RECORD_FM_VIRTUAL:
     *  USECASE_INCALL_REC_UPLINK:
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index 511d774..a5b97ac 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -264,6 +264,12 @@
 #define QCHAT_CALL_PCM_DEVICE_OF_EXT_CODEC 28
 #define VOWLAN_CALL_PCM_DEVICE 16
 
+#define VOICEMMODE1_CALL_PCM_DEVICE 26
+#define VOICEMMODE2_CALL_PCM_DEVICE 27
+
+#define VOICEMMODE1_CALL_PCM_DEVICE_OF_EXT_CODEC 29
+#define VOICEMMODE2_CALL_PCM_DEVICE_OF_EXT_CODEC 30
+
 #define AFE_PROXY_PLAYBACK_PCM_DEVICE 7
 #define AFE_PROXY_RECORD_PCM_DEVICE 8
 
diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp
index a1becd8..b0707d7 100644
--- a/policy_hal/AudioPolicyManager.cpp
+++ b/policy_hal/AudioPolicyManager.cpp
@@ -907,6 +907,53 @@
         mLimitRingtoneVolume = false;
     }
 }
+
+void AudioPolicyManagerCustom::setForceUse(audio_policy_force_use_t usage,
+                                         audio_policy_forced_cfg_t config)
+{
+    ALOGV("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mEngine->getPhoneState());
+
+    if (mEngine->setForceUse(usage, config) != NO_ERROR) {
+        ALOGW("setForceUse() could not set force cfg %d for usage %d", config, usage);
+        return;
+    }
+    bool forceVolumeReeval = (usage == AUDIO_POLICY_FORCE_FOR_COMMUNICATION) ||
+            (usage == AUDIO_POLICY_FORCE_FOR_DOCK) ||
+            (usage == AUDIO_POLICY_FORCE_FOR_SYSTEM);
+
+    // check for device and output changes triggered by new force usage
+    checkA2dpSuspend();
+    checkOutputForAllStrategies();
+    updateDevicesAndOutputs();
+    if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
+        audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, true /*fromCache*/);
+        updateCallRouting(newDevice);
+    }
+    // Use reverse loop to make sure any low latency usecases (generally tones)
+    // are not routed before non LL usecases (generally music).
+    // We can safely assume that LL output would always have lower index,
+    // and use this work-around to avoid routing of output with music stream
+    // from the context of short lived LL output.
+    // Note: in case output's share backend(HAL sharing is implicit) all outputs
+    //       gets routing update while processing first output itself.
+    for (size_t i = mOutputs.size(); i > 0; i--) {
+        sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(i-1);
+        audio_devices_t newDevice = getNewOutputDevice(outputDesc, true /*fromCache*/);
+        if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || outputDesc != mPrimaryOutput) {
+            setOutputDevice(outputDesc, newDevice, (newDevice != AUDIO_DEVICE_NONE));
+        }
+        if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) {
+            applyStreamVolumes(outputDesc, newDevice, 0, true);
+        }
+    }
+
+    audio_io_handle_t activeInput = mInputs.getActiveInput();
+    if (activeInput != 0) {
+        setInputDevice(activeInput, getNewInputDevice(activeInput));
+    }
+
+}
+
 status_t AudioPolicyManagerCustom::stopSource(sp<SwAudioOutputDescriptor> outputDesc,
                                             audio_stream_type_t stream,
                                             bool forceDeviceUpdate)
diff --git a/policy_hal/AudioPolicyManager.h b/policy_hal/AudioPolicyManager.h
index 55bb05c..dfaad65 100644
--- a/policy_hal/AudioPolicyManager.h
+++ b/policy_hal/AudioPolicyManager.h
@@ -54,6 +54,8 @@
                                           const char *device_address,
                                           const char *device_name);
         virtual void setPhoneState(audio_mode_t state);
+        virtual void setForceUse(audio_policy_force_use_t usage,
+                                 audio_policy_forced_cfg_t config);
 
         virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo);
 
diff --git a/visualizer/offload_visualizer.c b/visualizer/offload_visualizer.c
index d363b77..b2f0952 100644
--- a/visualizer/offload_visualizer.c
+++ b/visualizer/offload_visualizer.c
@@ -300,20 +300,40 @@
     return false;
 }
 
-int configure_proxy_capture(struct mixer *mixer, int value) {
-    const char *proxy_ctl_name = "AFE_PCM_RX Audio Mixer MultiMedia4";
+int set_control(const char* name, struct mixer *mixer, int value) {
     struct mixer_ctl *ctl;
 
+    ctl = mixer_get_ctl_by_name(mixer, name);
+    if (ctl == NULL) {
+        ALOGW("%s: could not get %s ctl", __func__, name);
+        return -EINVAL;
+    }
+    if (mixer_ctl_set_value(ctl, 0, value) != 0) {
+        ALOGW("%s: error setting value %d on %s ", __func__, value, name);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+int configure_proxy_capture(struct mixer *mixer, int value) {
+    int retval = 0;
+
     if (value && acdb_send_audio_cal)
         acdb_send_audio_cal(AFE_PROXY_ACDB_ID, ACDB_DEV_TYPE_OUT);
 
-    ctl = mixer_get_ctl_by_name(mixer, proxy_ctl_name);
-    if (ctl == NULL) {
-        ALOGW("%s: could not get %s ctl", __func__, proxy_ctl_name);
-        return -EINVAL;
-    }
-    if (mixer_ctl_set_value(ctl, 0, value) != 0)
-        ALOGW("%s: error setting value %d on %s ", __func__, value, proxy_ctl_name);
+    retval = set_control("AFE_PCM_RX Audio Mixer MultiMedia4", mixer, value);
+
+    if (retval != 0)
+        return retval;
+
+    // Extending visualizer to capture for compress2 path as well.
+    // for extending it to multiple offload either this needs to be extended
+    // or need to find better solution to enable only active offload sessions
+
+    retval = set_control("AFE_PCM_RX Audio Mixer MultiMedia7", mixer, value);
+    if (retval != 0)
+        return retval;
 
     return 0;
 }