audio_hal: add incall recording feature

The uplink, downlink and the combination of both can be
recorded using sound recorder app. Add support for incall
recording feature in audio HAL.

Change-Id: Ia828ab5b3af8044d82b6ef8eb989ae0ba9bbba16
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 3155ab6..0411b34 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -90,6 +90,9 @@
     [USECASE_VOICE2_CALL] = "voice2-call",
     [USECASE_VOLTE_CALL] = "volte-call",
     [USECASE_QCHAT_CALL] = "qchat-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",
 };
 
 
@@ -619,6 +622,14 @@
     struct audio_device *adev = in->dev;
 
     ALOGV("%s: enter: usecase(%d)", __func__, in->usecase);
+
+    /* Check if source matches incall recording usecase criteria */
+    ret = voice_check_and_set_incall_rec_usecase(adev, in);
+    if (ret)
+        goto error_config;
+    else
+        ALOGV("%s: usecase(%d)", __func__, in->usecase);
+
     in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE);
     if (in->pcm_device_id < 0) {
         ALOGE("%s: Could not find PCM device id for the usecase(%d)",
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 2eb1616..9b397b4 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -68,6 +68,10 @@
     USECASE_VOLTE_CALL,
     USECASE_QCHAT_CALL,
 
+    USECASE_INCALL_REC_UPLINK,
+    USECASE_INCALL_REC_DOWNLINK,
+    USECASE_INCALL_REC_UPLINK_AND_DOWNLINK,
+
     AUDIO_USECASE_MAX
 } audio_usecase_t;
 
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index a2eefdd..78d06c5 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -883,3 +883,9 @@
     LOGE("%s: Not implemented", __func__);
     return -ENOSYS;
 }
+
+int platform_set_incall_recoding_session_id(void *platform, uint32_t session_id)
+{
+    LOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index ee069d7..44d9b42 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -99,7 +99,7 @@
                                             LOWLATENCY_PCM_DEVICE},
     [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {MULTI_CHANNEL_PCM_DEVICE,
                                          MULTI_CHANNEL_PCM_DEVICE},
-    [USECASE_AUDIO_RECORD] = {DEEP_BUFFER_PCM_DEVICE, DEEP_BUFFER_PCM_DEVICE},
+    [USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE},
     [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
                                           LOWLATENCY_PCM_DEVICE},
     [USECASE_AUDIO_PLAYBACK_FM] = {FM_PLAYBACK_PCM_DEVICE, FM_CAPTURE_PCM_DEVICE},
@@ -107,6 +107,12 @@
     [USECASE_VOICE2_CALL] = {VOICE2_CALL_PCM_DEVICE, VOICE2_CALL_PCM_DEVICE},
     [USECASE_VOLTE_CALL] = {VOLTE_CALL_PCM_DEVICE, VOLTE_CALL_PCM_DEVICE},
     [USECASE_QCHAT_CALL] = {QCHAT_CALL_PCM_DEVICE, QCHAT_CALL_PCM_DEVICE},
+    [USECASE_INCALL_REC_UPLINK] = {AUDIO_RECORD_PCM_DEVICE,
+                                   AUDIO_RECORD_PCM_DEVICE},
+    [USECASE_INCALL_REC_DOWNLINK] = {AUDIO_RECORD_PCM_DEVICE,
+                                     AUDIO_RECORD_PCM_DEVICE},
+    [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = {AUDIO_RECORD_PCM_DEVICE,
+                                                AUDIO_RECORD_PCM_DEVICE},
 };
 
 /* Array to store sound devices */
@@ -947,6 +953,36 @@
     return ret;
 }
 
+int platform_set_incall_recoding_session_id(void *platform,
+                                            uint32_t session_id)
+{
+    int ret = 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "Voc VSID";
+    int num_ctl_values;
+    int i;
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        ret = -EINVAL;
+    } else {
+        num_ctl_values = mixer_ctl_get_num_values(ctl);
+        for (i = 0; i < num_ctl_values; i++) {
+            if (mixer_ctl_set_value(ctl, i, session_id)) {
+                ALOGV("Error: invalid session_id: %x", session_id);
+                ret = -EINVAL;
+                break;
+            }
+        }
+    }
+
+    return ret;
+}
+
 void platform_get_parameters(void *platform,
                             struct str_parms *query,
                             struct str_parms *reply)
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index dd8dfda..9d0ff24 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -138,6 +138,7 @@
 #define AUDIO_CAPTURE_PERIOD_COUNT 2
 
 #define DEEP_BUFFER_PCM_DEVICE 0
+#define AUDIO_RECORD_PCM_DEVICE 0
 #define MULTI_CHANNEL_PCM_DEVICE 1
 #define VOICE_CALL_PCM_DEVICE 2
 #define FM_PLAYBACK_PCM_DEVICE 5
diff --git a/hal/platform_api.h b/hal/platform_api.h
index b1d0420..39c94e8 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -41,6 +41,6 @@
 void platform_get_parameters(void *platform, struct str_parms *query,
                              struct str_parms *reply);
 int platform_set_parameters(void *platform, struct str_parms *parms);
-
+int platform_set_incall_recoding_session_id(void *platform, uint32_t session_id);
 
 #endif // QCOM_AUDIO_PLATFORM_API_H
diff --git a/hal/voice.c b/hal/voice.c
index 2b1ac87..7b40d1a 100644
--- a/hal/voice.c
+++ b/hal/voice.c
@@ -119,7 +119,7 @@
     struct audio_usecase *uc_info;
     int pcm_dev_rx_id, pcm_dev_tx_id;
     struct voice_session *session = NULL;
-
+    struct pcm_config voice_config = pcm_config_voice_call;
     ALOGD("%s: enter", __func__);
 
     session = (struct voice_session *)voice_get_session_from_use_case(adev, usecase_id);
@@ -150,7 +150,7 @@
           __func__, SOUND_CARD, pcm_dev_rx_id);
     session->pcm_rx = pcm_open(SOUND_CARD,
                                pcm_dev_rx_id,
-                               PCM_OUT, &pcm_config_voice_call);
+                               PCM_OUT, &voice_config);
     if (session->pcm_rx && !pcm_is_ready(session->pcm_rx)) {
         ALOGE("%s: %s", __func__, pcm_get_error(session->pcm_rx));
         ret = -EIO;
@@ -161,7 +161,7 @@
           __func__, SOUND_CARD, pcm_dev_tx_id);
     session->pcm_tx = pcm_open(SOUND_CARD,
                                pcm_dev_tx_id,
-                               PCM_IN, &pcm_config_voice_call);
+                               PCM_IN, &voice_config);
     if (session->pcm_tx && !pcm_is_ready(session->pcm_tx)) {
         ALOGE("%s: %s", __func__, pcm_get_error(session->pcm_tx));
         ret = -EIO;
@@ -199,6 +199,54 @@
     return in_call;
 }
 
+uint32_t voice_get_active_session_id(struct audio_device *adev)
+{
+    int ret = 0;
+    uint32_t session_id;
+
+    ret = voice_extn_get_active_session_id(adev, &session_id);
+    if (ret == -ENOSYS) {
+        session_id = VOICE_VSID;
+    }
+    return session_id;
+}
+
+int voice_check_and_set_incall_rec_usecase(struct audio_device *adev,
+                                       struct stream_in *in)
+{
+    int ret = 0;
+    uint32_t session_id;
+    int usecase_id;
+
+    if (voice_is_in_call(adev)) {
+        switch (in->source) {
+        case AUDIO_SOURCE_VOICE_UPLINK:
+            in->usecase = USECASE_INCALL_REC_UPLINK;
+            break;
+        case AUDIO_SOURCE_VOICE_DOWNLINK:
+            in->usecase = USECASE_INCALL_REC_DOWNLINK;
+            break;
+        case AUDIO_SOURCE_VOICE_CALL:
+            in->usecase = USECASE_INCALL_REC_UPLINK_AND_DOWNLINK;
+            break;
+        default:
+            ALOGV("%s: Source type %d doesnt match incall recording criteria",
+                  __func__, in->source);
+            return ret;
+        }
+
+        in->config = pcm_config_voice_call;
+        session_id = voice_get_active_session_id(adev);
+        ret = platform_set_incall_recoding_session_id(adev->platform,
+                                                      session_id);
+        ALOGV("%s: Update usecase to %d",__func__, in->usecase);
+    } else {
+        ALOGV("%s: voice call not active", __func__);
+    }
+
+    return ret;
+}
+
 int voice_set_mic_mute(struct audio_device *adev, bool state)
 {
     int err = 0;
diff --git a/hal/voice.h b/hal/voice.h
index 22c359d..d5e5a8d 100644
--- a/hal/voice.h
+++ b/hal/voice.h
@@ -37,6 +37,7 @@
 
 struct audio_device;
 struct str_parms;
+struct stream_in;
 
 struct call_state {
     int current;
@@ -65,4 +66,6 @@
 int voice_set_mic_mute(struct audio_device *dev, bool state);
 bool voice_get_mic_mute(struct audio_device *dev);
 int voice_set_volume(struct audio_device *adev, float volume);
+int voice_check_and_set_incall_rec_usecase(struct audio_device *adev,
+                                       struct stream_in *in);
 #endif //VOICE_H
diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c
index ac3d9f2..29f12d4 100644
--- a/hal/voice_extn/voice_extn.c
+++ b/hal/voice_extn/voice_extn.c
@@ -103,6 +103,24 @@
     return usecase_id;
 }
 
+int voice_extn_get_active_session_id(struct audio_device *adev,
+                                     uint32_t *session_id)
+{
+    struct voice_session *session = NULL;
+    int i = 0;
+    *session_id = 0;
+
+    for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+        session = &adev->voice.session[i];
+        if(session->state.current == CALL_ACTIVE){
+            *session_id = session->vsid;
+            break;
+        }
+    }
+
+    return 0;
+}
+
 int voice_extn_is_in_call(struct audio_device *adev, bool *in_call)
 {
     struct voice_session *session = NULL;
diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h
index ae983e1..568f716 100644
--- a/hal/voice_extn/voice_extn.h
+++ b/hal/voice_extn/voice_extn.h
@@ -28,6 +28,8 @@
 int voice_extn_set_parameters(struct audio_device *adev,
                               struct str_parms *parms);
 int voice_extn_is_in_call(struct audio_device *adev, bool *in_call);
+int voice_extn_get_active_session_id(struct audio_device *adev,
+                                     uint32_t *session_id);
 
 #ifndef MULTI_VOICE_SESSION_ENABLED
 int voice_extn_update_calls(struct audio_device *adev)
@@ -57,6 +59,11 @@
 {
     return -ENOSYS;
 }
+int voice_extn_get_active_session_id(struct audio_device *adev,
+                                     uint32_t *session_id)
+{
+    return -ENOSYS;
+}
 #endif
 
 #endif //VOICE_EXTN_H