hal: start voip driver independent of voip output stream

- Voip driver requires voip output stream to be opened
to start itself. But it is possible that some applications
may use voip input and normal audio output. Code changes are
done to handle this scenario.
- It is possible that some applications may use different
sample rates for voip input and voip output streams. It is
handled now in such a way that, if the sample rate of the
secondly opening stream does not match with that of the
first one, the second stream will not be allowed to open
voice path for VoIP.

Change-Id: Id9d86181eeee2c4ea0aa49a723ca92c1961a559b
CRs-fixed: 601785
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 04a7aba..d8db6b2 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -1914,11 +1914,10 @@
                 (voice_extn_compress_voip_is_format_supported(in->format)) &&
                 (in->config.rate == 8000 || in->config.rate == 16000) &&
                 (popcount(in->channel_mask) == 1)) {
-                ret = voice_extn_compress_voip_open_input_stream(in);
-                if (ret != 0) {
+                err = voice_extn_compress_voip_open_input_stream(in);
+                if (err != 0) {
                     ALOGE("%s: Compress voip input cannot be opened, error:%d",
-                          __func__, ret);
-                    goto done;
+                          __func__, err);
                 }
             }
         }
diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c
index 4db46f6..47ac2c8 100644
--- a/hal/voice_extn/compress_voip.c
+++ b/hal/voice_extn/compress_voip.c
@@ -59,8 +59,9 @@
     struct pcm *pcm_rx;
     struct pcm *pcm_tx;
     struct stream_out *out_stream;
-    int ref_count;
-    int out_stream_count;
+    uint32_t out_stream_count;
+    uint32_t in_stream_count;
+    uint32_t sample_rate;
 };
 
 #define MODE_IS127              0x2
@@ -78,13 +79,15 @@
 #define AUDIO_PARAMETER_VALUE_VOIP_TRUE             "true"
 #define AUDIO_PARAMETER_KEY_VOIP_CHECK              "voip_flag"
 #define AUDIO_PARAMETER_KEY_VOIP_OUT_STREAM_COUNT   "voip_out_stream_count"
+#define AUDIO_PARAMETER_KEY_VOIP_SAMPLE_RATE        "voip_sample_rate"
 
 static struct voip_data voip_data = {
   .pcm_rx = NULL,
   .pcm_tx = NULL,
   .out_stream = NULL,
-  .ref_count = 0,
-  .out_stream_count = 0
+  .out_stream_count = 0,
+  .in_stream_count = 0,
+  .sample_rate = 0
 };
 
 static int voip_set_volume(struct audio_device *adev, int volume);
@@ -280,10 +283,10 @@
     int i, ret = 0;
     struct audio_usecase *uc_info;
 
-    ALOGD("%s: enter, ref_count=%d", __func__, voip_data.ref_count);
-    voip_data.ref_count--;
+    ALOGD("%s: enter, out_stream_count=%d, in_stream_count=%d",
+           __func__, voip_data.out_stream_count, voip_data.in_stream_count);
 
-    if (!voip_data.ref_count) {
+    if (!voip_data.out_stream_count && !voip_data.in_stream_count) {
         uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
         if (uc_info == NULL) {
             ALOGE("%s: Could not find the usecase (%d) in the list",
@@ -310,8 +313,10 @@
 
         list_remove(&uc_info->list);
         free(uc_info);
+        voip_data.sample_rate = 0;
     } else
-        ALOGV("%s: NO-OP because ref_count=%d", __func__, voip_data.ref_count);
+        ALOGV("%s: NO-OP because out_stream_count=%d, in_stream_count=%d",
+               __func__, voip_data.out_stream_count, voip_data.in_stream_count);
 
     ALOGV("%s: exit: status(%d)", __func__, ret);
     return ret;
@@ -327,12 +332,15 @@
     ALOGD("%s: enter", __func__);
 
     uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
-    if ((uc_info == NULL) && (voip_data.out_stream)) {
+    if (uc_info == NULL) {
         ALOGV("%s: voip usecase is added to the list", __func__);
         uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
         uc_info->id = USECASE_COMPRESS_VOIP_CALL;
         uc_info->type = VOIP_CALL;
-        uc_info->stream.out = voip_data.out_stream;
+        if (voip_data.out_stream)
+            uc_info->stream.out = voip_data.out_stream;
+        else
+            uc_info->stream.out = adev->primary_output;
         uc_info->in_snd_device = SND_DEVICE_NONE;
         uc_info->out_snd_device = SND_DEVICE_NONE;
 
@@ -388,12 +396,15 @@
             ALOGE("%s: error %d\n", __func__, ret);
             goto error_start_voip;
         }
-        voip_data.ref_count = 0;
-    }
-    else
+    } else {
         ALOGV("%s: voip usecase is already enabled", __func__);
+        if (voip_data.out_stream)
+            uc_info->stream.out = voip_data.out_stream;
+        else
+            uc_info->stream.out = adev->primary_output;
+        select_devices(adev, USECASE_COMPRESS_VOIP_CALL);
+    }
 
-    voip_data.ref_count++;
     return 0;
 
 error_start_voip:
@@ -472,6 +483,13 @@
         str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_OUT_STREAM_COUNT,
                           voip_data.out_stream_count);
     }
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOIP_SAMPLE_RATE,
+                            value, sizeof(value));
+    if (ret >= 0) {
+        str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_SAMPLE_RATE,
+                          voip_data.sample_rate);
+    }
 }
 
 void voice_extn_compress_voip_out_get_parameters(struct stream_out *out,
@@ -576,9 +594,9 @@
 
     ALOGD("%s: enter", __func__);
 
+    voip_data.out_stream_count--;
     ret = voip_stop_call(adev);
     voip_data.out_stream = NULL;
-    voip_data.out_stream_count--;
 
     ALOGV("%s: exit: status(%d)", __func__, ret);
     return ret;
@@ -600,7 +618,7 @@
 
     voip_data.out_stream = out;
     voip_data.out_stream_count++;
-
+    voip_data.sample_rate = out->sample_rate;
     ret = voip_set_mode(out->dev, out->format);
 
     ALOGV("%s: exit", __func__);
@@ -615,6 +633,7 @@
 
     ALOGD("%s: enter", __func__);
 
+    voip_data.in_stream_count--;
     status = voip_stop_call(adev);
 
     ALOGV("%s: exit: status(%d)", __func__, status);
@@ -630,15 +649,25 @@
 
     ALOGD("%s: enter", __func__);
 
+    if ((voip_data.sample_rate != 0) &&
+        (voip_data.sample_rate != in->config.rate)) {
+        ret = -ENOTSUP;
+        goto done;
+    } else {
+        voip_data.sample_rate = in->config.rate;
+    }
+
     in->usecase = USECASE_COMPRESS_VOIP_CALL;
     if (in->config.rate == 16000)
         in->config = pcm_config_voip_wb;
     else
         in->config = pcm_config_voip_nb;
 
+    voip_data.in_stream_count++;
     ret = voip_set_mode(in->dev, in->format);
 
-    ALOGV("%s: exit", __func__);
+done:
+    ALOGV("%s: exit, ret=%d", __func__, ret);
     return ret;
 }
 
@@ -734,7 +763,8 @@
     if (ret) {
         if ((popcount(config->channel_mask) == 1) &&
             (config->sample_rate == 8000 || config->sample_rate == 16000))
-            ret = true;
+            ret = ((voip_data.sample_rate == 0) ? true:
+                    (voip_data.sample_rate == config->sample_rate));
         else
             ret = false;
     }