hal: Add support for compressed voip

Add support to enable voip calls using compressed
audio formats.

Change-Id: If20493b75befbcc56945e4309c8f01384948a7b5
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 209c13e..9b59e4a 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -50,6 +50,7 @@
 #include "platform_api.h"
 #include <platform.h>
 #include "audio_extn.h"
+#include "voice_extn.h"
 
 #include "sound/compress_params.h"
 
@@ -112,6 +113,7 @@
     [USECASE_VOICE2_CALL] = "voice2-call",
     [USECASE_VOLTE_CALL] = "volte-call",
     [USECASE_QCHAT_CALL] = "qchat-call",
+    [USECASE_COMPRESS_VOIP_CALL] = "compress-voip-call",
     [USECASE_INCALL_REC_UPLINK] = "incall-rec-uplink",
     [USECASE_INCALL_REC_DOWNLINK] = "incall-rec-downlink",
     [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = "incall-rec-uplink-and-downlink",
@@ -573,6 +575,7 @@
     snd_device_t in_snd_device = SND_DEVICE_NONE;
     struct audio_usecase *usecase = NULL;
     struct audio_usecase *vc_usecase = NULL;
+    struct audio_usecase *voip_usecase = NULL;
     struct listnode *node;
     int status = 0;
 
@@ -582,7 +585,8 @@
         return -EINVAL;
     }
 
-    if (usecase->type == VOICE_CALL) {
+    if ((usecase->type == VOICE_CALL) ||
+        (usecase->type == VOIP_CALL)) {
         out_snd_device = platform_get_output_snd_device(adev->platform,
                                                         usecase->stream.out->devices);
         in_snd_device = platform_get_input_snd_device(adev->platform, usecase->stream.out->devices);
@@ -602,6 +606,12 @@
                 in_snd_device = vc_usecase->in_snd_device;
                 out_snd_device = vc_usecase->out_snd_device;
             }
+        } else if (voice_extn_compress_voip_is_active(adev)) {
+            voip_usecase = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
+            if (voip_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) {
+                    in_snd_device = voip_usecase->in_snd_device;
+                    out_snd_device = voip_usecase->out_snd_device;
+            }
         }
         if (usecase->type == PCM_PLAYBACK) {
             usecase->devices = usecase->stream.out->devices;
@@ -645,8 +655,8 @@
      * and enable both RX and TX devices though one of them is same as current
      * device.
      */
-    if (usecase->type == VOICE_CALL) {
-        disable_all_usecases_of_type(adev, VOICE_CALL, true);
+    if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) {
+        disable_all_usecases_of_type(adev, usecase->type, true);
         status = platform_switch_voice_call_device_pre(adev->platform);
     }
 
@@ -673,7 +683,7 @@
         enable_snd_device(adev, in_snd_device, false);
     }
 
-    if (usecase->type == VOICE_CALL)
+    if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL)
         status = platform_switch_voice_call_device_post(adev->platform,
                                                         out_snd_device,
                                                         in_snd_device);
@@ -683,8 +693,8 @@
     usecase->in_snd_device = in_snd_device;
     usecase->out_snd_device = out_snd_device;
 
-    if (usecase->type == VOICE_CALL)
-        enable_all_usecases_of_type(adev, VOICE_CALL, true);
+    if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL)
+        enable_all_usecases_of_type(adev, usecase->type, true);
     else
         enable_audio_route(adev, usecase, true);
 
@@ -1115,7 +1125,8 @@
 {
     int ret = 0;
 
-    if (format != AUDIO_FORMAT_PCM_16_BIT) ret = -EINVAL;
+    if ((format != AUDIO_FORMAT_PCM_16_BIT) &&
+        !voice_extn_compress_voip_is_format_supported(format)) ret = -EINVAL;
 
     switch (channel_count) {
     case 1:
@@ -1181,9 +1192,10 @@
 {
     struct stream_out *out = (struct stream_out *)stream;
 
-    if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+    if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD)
         return out->compr_config.fragment_size;
-    }
+    else if(out->usecase == USECASE_COMPRESS_VOIP_CALL)
+        return voice_extn_compress_voip_out_get_buffer_size(out);
 
     return out->config.period_size * audio_stream_frame_size(stream);
 }
@@ -1214,6 +1226,13 @@
 
     ALOGV("%s: enter: usecase(%d: %s)", __func__,
           out->usecase, use_case_table[out->usecase]);
+    if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
+        /* Ignore standby in case of voip call because the voip output
+         * stream is closed in adev_close_output_stream()
+         */
+        ALOGV("%s: Ignore Standby in VOIP call", __func__);
+        return 0;
+    }
 
     pthread_mutex_lock(&out->lock);
     pthread_mutex_lock(&adev->lock);
@@ -1401,7 +1420,11 @@
         str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value);
         str = str_parms_to_str(reply);
     } else {
-        str = strdup(keys);
+        voice_extn_out_get_parameters(out, query, reply);
+        str = str_parms_to_str(reply);
+        if (!strncmp(str, "", sizeof(""))) {
+           str = strdup(keys);
+        }
     }
     str_parms_destroy(query);
     str_parms_destroy(reply);
@@ -1461,7 +1484,10 @@
     if (out->standby) {
         out->standby = false;
         pthread_mutex_lock(&adev->lock);
-        ret = start_output_stream(out);
+        if (out->usecase == USECASE_COMPRESS_VOIP_CALL)
+            ret = voice_extn_compress_voip_start_output_stream(out);
+        else
+            ret = start_output_stream(out);
         pthread_mutex_unlock(&adev->lock);
         /* ToDo: If use case is compress offload should return 0 */
         if (ret != 0) {
@@ -1686,6 +1712,9 @@
 {
     struct stream_in *in = (struct stream_in *)stream;
 
+    if(in->usecase == USECASE_COMPRESS_VOIP_CALL)
+        return voice_extn_compress_voip_in_get_buffer_size(in);
+
     return in->config.period_size * audio_stream_frame_size(stream);
 }
 
@@ -1698,7 +1727,9 @@
 
 static audio_format_t in_get_format(const struct audio_stream *stream)
 {
-    return AUDIO_FORMAT_PCM_16_BIT;
+    struct stream_in *in = (struct stream_in *)stream;
+
+    return in->format;
 }
 
 static int in_set_format(struct audio_stream *stream, audio_format_t format)
@@ -1712,6 +1743,15 @@
     struct audio_device *adev = in->dev;
     int status = 0;
     ALOGV("%s: enter", __func__);
+
+    if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
+        /* Ignore standby in case of voip call because the voip input
+         * stream is closed in adev_close_input_stream()
+         */
+        ALOGV("%s: Ignore Standby in VOIP call", __func__);
+        return status;
+    }
+
     pthread_mutex_lock(&in->lock);
     if (!in->standby) {
         in->standby = true;
@@ -1779,7 +1819,21 @@
 static char* in_get_parameters(const struct audio_stream *stream,
                                const char *keys)
 {
-    return strdup("");
+    struct stream_in *in = (struct stream_in *)stream;
+    struct str_parms *query = str_parms_create_str(keys);
+    char *str;
+    char value[256];
+    struct str_parms *reply = str_parms_create();
+    ALOGV("%s: enter: keys - %s", __func__, keys);
+
+    voice_extn_in_get_parameters(in, query, reply);
+
+    str = str_parms_to_str(reply);
+    str_parms_destroy(query);
+    str_parms_destroy(reply);
+
+    ALOGV("%s: exit: returns - %s", __func__, str);
+    return str;
 }
 
 static int in_set_gain(struct audio_stream_in *stream, float gain)
@@ -1797,7 +1851,10 @@
     pthread_mutex_lock(&in->lock);
     if (in->standby) {
         pthread_mutex_lock(&adev->lock);
-        ret = start_input_stream(in);
+        if (in->usecase == USECASE_COMPRESS_VOIP_CALL)
+            ret = voice_extn_compress_voip_start_input_stream(in);
+        else
+            ret = start_input_stream(in);
         pthread_mutex_unlock(&adev->lock);
         if (ret != 0) {
             goto exit;
@@ -1932,6 +1989,17 @@
         out->config.rate = config->sample_rate;
         out->config.channels = popcount(out->channel_mask);
         out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels * 2);
+    } else if ((out->dev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
+               (out->flags == (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_VOIP_RX)) &&
+               (voice_extn_compress_voip_is_format_supported(out->format))) {
+        ret = voice_extn_compress_voip_open_output_stream(out);
+        if (ret != 0) {
+            ALOGE("%s: Compress voip output cannot be opened, error:%d",
+                  __func__, ret);
+            goto error_open;
+        }
+        out->config.rate = config->sample_rate;
+        out->sample_rate = config->sample_rate;
     } else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
         if (config->offload_info.version != AUDIO_INFO_INITIALIZER.version ||
             config->offload_info.size != AUDIO_INFO_INITIALIZER.size) {
@@ -2065,9 +2133,18 @@
 {
     struct stream_out *out = (struct stream_out *)stream;
     struct audio_device *adev = out->dev;
+    int ret = 0;
 
     ALOGV("%s: enter", __func__);
-    out_standby(&stream->common);
+    if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
+        ret = voice_extn_compress_voip_close_output_stream(&stream->common);
+        if(ret != 0)
+            ALOGE("%s: Compress voip output cannot be closed, error:%d",
+                  __func__, ret);
+    }
+    else
+        out_standby(&stream->common);
+
     if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
         destroy_offload_callback_thread(out);
 
@@ -2295,7 +2372,18 @@
     in->usecase = USECASE_AUDIO_RECORD;
     in->config = pcm_config_audio_capture;
     in->config.rate = config->sample_rate;
+    in->format = config->format;
 
+    if ((in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
+        (voice_extn_compress_voip_is_format_supported(in->format))) {
+        ret = voice_extn_compress_voip_open_input_stream(in);
+        if (ret != 0)
+        {
+            ALOGE("%s: Compress voip input cannot be opened, error:%d",
+                  __func__, ret);
+            goto err_open;
+        }
+    }
     if (channel_count == 6) {
         if(audio_extn_ssr_get_enabled()) {
             if(audio_extn_ssr_init(adev, in)) {
@@ -2329,10 +2417,18 @@
 static void adev_close_input_stream(struct audio_hw_device *dev,
                                     struct audio_stream_in *stream)
 {
+    int ret;
     struct stream_in *in = (struct stream_in *)stream;
     ALOGV("%s", __func__);
 
-    in_standby(&stream->common);
+    if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
+        ret = voice_extn_compress_voip_close_input_stream(&stream->common);
+        if (ret != 0)
+            ALOGE("%s: Compress voip input cannot be closed, error:%d",
+                  __func__, ret);
+    } else
+        in_standby(&stream->common);
+
     if (audio_extn_ssr_get_enabled() && (popcount(in->channel_mask) == 6)) {
         audio_extn_ssr_deinit();
     }