Merge "hal: add incall music delivery feature"
diff --git a/hal/Android.mk b/hal/Android.mk
index cc6b62e..be67ba0 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -43,6 +43,10 @@
     LOCAL_CFLAGS += -DAFE_PROXY_ENABLED
 endif
 
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_INCALL_MUSIC)),true)
+LOCAL_CFLAGS += -DINCALL_MUSIC_ENABLED
+endif
+
 ifneq ($(strip $(AUDIO_FEATURE_DISABLED_FM)),true)
     LOCAL_CFLAGS += -DFM_ENABLED
     LOCAL_SRC_FILES += audio_extn/fm.c
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 1bcb25a..aa7e6a6 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -114,6 +114,8 @@
     [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",
+    [USECASE_INCALL_MUSIC_UPLINK] = "incall_music_uplink",
+    [USECASE_INCALL_MUSIC_UPLINK2] = "incall_music_uplink2",
 };
 
 
@@ -1925,6 +1927,13 @@
         ALOGV("%s: offloaded output offload_info version %04x bit rate %d",
                 __func__, config->offload_info.version,
                 config->offload_info.bit_rate);
+    } else if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) {
+        ret = voice_check_and_set_incall_music_usecase(adev, out);
+        if (ret != 0) {
+            ALOGE("%s: Incall music delivery usecase cannot be set error:%d",
+                  __func__, ret);
+            goto error_open;
+        }
     } else {
         out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
         out->config = pcm_config_low_latency;
@@ -2146,6 +2155,7 @@
     struct audio_device *adev = (struct audio_device *)dev;
     pthread_mutex_lock(&adev->lock);
     if (adev->mode != mode) {
+        ALOGD("%s mode %d\n", __func__, mode);
         adev->mode = mode;
     }
     pthread_mutex_unlock(&adev->lock);
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index c43b557..965ac62 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -78,6 +78,9 @@
     USECASE_INCALL_REC_DOWNLINK,
     USECASE_INCALL_REC_UPLINK_AND_DOWNLINK,
 
+    USECASE_INCALL_MUSIC_UPLINK,
+    USECASE_INCALL_MUSIC_UPLINK2,
+
     AUDIO_USECASE_MAX
 } audio_usecase_t;
 
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 134fdbb..1734ced 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -113,6 +113,10 @@
                                      AUDIO_RECORD_PCM_DEVICE},
     [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = {AUDIO_RECORD_PCM_DEVICE,
                                                 AUDIO_RECORD_PCM_DEVICE},
+    [USECASE_INCALL_MUSIC_UPLINK] = {INCALL_MUSIC_UPLINK_PCM_DEVICE,
+                                     INCALL_MUSIC_UPLINK_PCM_DEVICE},
+    [USECASE_INCALL_MUSIC_UPLINK2] = {INCALL_MUSIC_UPLINK2_PCM_DEVICE,
+                                      INCALL_MUSIC_UPLINK2_PCM_DEVICE},
 };
 
 /* Array to store sound devices */
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index fe55f1b..9212307 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -150,6 +150,8 @@
 #define VOICE_CALL_PCM_DEVICE 2
 #define FM_PLAYBACK_PCM_DEVICE 5
 #define FM_CAPTURE_PCM_DEVICE  6
+#define INCALL_MUSIC_UPLINK_PCM_DEVICE 1
+#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16
 
 #ifdef PLATFORM_MSM8x26
 #define VOICE2_CALL_PCM_DEVICE 14
diff --git a/hal/voice.c b/hal/voice.c
index 190df7c..39e2dd9 100755
--- a/hal/voice.c
+++ b/hal/voice.c
@@ -249,6 +249,20 @@
     return ret;
 }
 
+int voice_check_and_set_incall_music_usecase(struct audio_device *adev,
+                                             struct stream_out *out)
+{
+    int ret = 0;
+
+    ret = voice_extn_check_and_set_incall_music_usecase(adev, out);
+    if (ret == -ENOSYS) {
+        /* Incall music delivery is used only for LCH call state */
+        ret = -EINVAL;
+    }
+
+    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 d5e5a8d..7f8b25b 100644
--- a/hal/voice.h
+++ b/hal/voice.h
@@ -38,6 +38,7 @@
 struct audio_device;
 struct str_parms;
 struct stream_in;
+struct stream_out;
 
 struct call_state {
     int current;
@@ -67,5 +68,7 @@
 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);
+                                           struct stream_in *in);
+int voice_check_and_set_incall_music_usecase(struct audio_device *adev,
+                                             struct stream_out *out);
 #endif //VOICE_H
diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c
index 29f12d4..903d2aa 100644
--- a/hal/voice_extn/voice_extn.c
+++ b/hal/voice_extn/voice_extn.c
@@ -17,8 +17,6 @@
  * limitations under the License.
  */
 
-#ifdef MULTI_VOICE_SESSION_ENABLED
-
 #define LOG_TAG "voice_extn"
 /*#define LOG_NDEBUG 0*/
 #define LOG_NDDEBUG 0
@@ -52,6 +50,17 @@
 #define CALL_HOLD           (BASE_CALL_STATE + 2)
 #define CALL_LOCAL_HOLD     (BASE_CALL_STATE + 3)
 
+struct pcm_config pcm_config_incall_music = {
+    .channels = 1,
+    .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
+    .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
+    .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
+    .format = PCM_FORMAT_S16_LE,
+    .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
+    .stop_threshold = INT_MAX,
+    .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
+};
+
 extern int start_call(struct audio_device *adev, audio_usecase_t usecase_id);
 extern int stop_call(struct audio_device *adev, audio_usecase_t usecase_id);
 int voice_extn_update_calls(struct audio_device *adev);
@@ -103,21 +112,28 @@
     return usecase_id;
 }
 
-int voice_extn_get_active_session_id(struct audio_device *adev,
-                                     uint32_t *session_id)
+static uint32_t get_session_id_with_state(struct audio_device *adev,
+                                          int call_state)
 {
     struct voice_session *session = NULL;
     int i = 0;
-    *session_id = 0;
+    uint32_t 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;
+        if(session->state.current == call_state){
+            session_id = session->vsid;
             break;
         }
     }
 
+    return session_id;
+}
+
+int voice_extn_get_active_session_id(struct audio_device *adev,
+                                     uint32_t *session_id)
+{
+    *session_id = get_session_id_with_state(adev, CALL_ACTIVE);
     return 0;
 }
 
@@ -155,6 +171,7 @@
     if (session) {
         session->state.new = call_state;
         voice_extn_is_in_call(adev, &is_in_call);
+        ALOGD("%s is_in_call:%d mode:%d\n", __func__, is_in_call, adev->mode);
         if (is_in_call || adev->mode == AUDIO_MODE_IN_CALL) {
             /* Device routing is not triggered for voice calls on the subsequent
              * subs, Hence update the call states if voice call is already
@@ -224,7 +241,7 @@
     for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
         usecase_id = voice_extn_get_usecase_for_session_idx(i);
         session = &adev->voice.session[i];
-        ALOGV("%s: cur_state=%d new_state=%d vsid=%x",
+        ALOGD("%s: cur_state=%d new_state=%d vsid=%x",
               __func__, session->state.current, session->state.new, session->vsid);
 
         switch(session->state.new)
@@ -233,7 +250,7 @@
             switch(session->state.current)
             {
             case CALL_INACTIVE:
-                ALOGD("%s: INACTIVE ->ACTIVE vsid:%x", __func__, session->vsid);
+                ALOGD("%s: INACTIVE -> ACTIVE vsid:%x", __func__, session->vsid);
                 ret = start_call(adev, usecase_id);
                 if(ret < 0) {
                     ALOGE("%s: voice_start_call() failed for usecase: %d\n",
@@ -243,15 +260,15 @@
                 break;
 
             case CALL_HOLD:
-                ALOGD("%s: HOLD ->ACTIVE vsid:%x", __func__, session->vsid);
+                ALOGD("%s: HOLD -> ACTIVE vsid:%x", __func__, session->vsid);
                 session->state.current = session->state.new;
                 break;
 
             case CALL_LOCAL_HOLD:
-                ALOGD("%s: LOCAL_HOLD ->ACTIVE vsid:%x", __func__, session->vsid);
+                ALOGD("%s: LOCAL_HOLD -> ACTIVE vsid:%x", __func__, session->vsid);
                 lch_mode = VOICE_LCH_STOP;
                 if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
-                    ALOGE("LOCAL_HOLD ->ACTIVE failed");
+                    ALOGE("LOCAL_HOLD -> ACTIVE failed");
                 } else {
                     session->state.current = session->state.new;
                 }
@@ -270,7 +287,7 @@
             case CALL_ACTIVE:
             case CALL_HOLD:
             case CALL_LOCAL_HOLD:
-                ALOGD("%s: ACTIVE/HOLD/LOCAL_HOLD ->INACTIVE vsid:%x", __func__, session->vsid);
+                ALOGD("%s: ACTIVE/HOLD/LOCAL_HOLD -> INACTIVE vsid:%x", __func__, session->vsid);
                 ret = stop_call(adev, usecase_id);
                 if(ret < 0) {
                     ALOGE("%s: voice_end_call() failed for usecase: %d\n",
@@ -290,15 +307,15 @@
             switch(session->state.current)
             {
             case CALL_ACTIVE:
-                ALOGD("%s: CALL_ACTIVE ->HOLD vsid:%x", __func__, session->vsid);
+                ALOGD("%s: CALL_ACTIVE -> HOLD vsid:%x", __func__, session->vsid);
                 session->state.current = session->state.new;
                 break;
 
             case CALL_LOCAL_HOLD:
-                ALOGD("%s: CALL_LOCAL_HOLD ->HOLD vsid:%x", __func__, session->vsid);
+                ALOGD("%s: CALL_LOCAL_HOLD -> HOLD vsid:%x", __func__, session->vsid);
                 lch_mode = VOICE_LCH_STOP;
                 if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
-                    ALOGE("LOCAL_HOLD ->HOLD failed");
+                    ALOGE("LOCAL_HOLD -> HOLD failed");
                 } else {
                     session->state.current = session->state.new;
                 }
@@ -316,10 +333,11 @@
             {
             case CALL_ACTIVE:
             case CALL_HOLD:
-                ALOGD("%s: ACTIVE/CALL_HOLD ->LOCAL_HOLD vsid:%x", __func__, session->vsid);
+                ALOGD("%s: ACTIVE/CALL_HOLD -> LOCAL_HOLD vsid:%x", __func__,
+                      session->vsid);
                 lch_mode = VOICE_LCH_START;
                 if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
-                    ALOGE("LOCAL_HOLD ->HOLD failed");
+                    ALOGE("LOCAL_HOLD -> HOLD failed");
                 } else {
                     session->state.current = session->state.new;
                 }
@@ -382,4 +400,25 @@
     return ret;
 }
 
-#endif
+int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev,
+                                                  struct stream_out *out)
+{
+    uint32_t session_id = 0;
+
+    session_id = get_session_id_with_state(adev, CALL_LOCAL_HOLD);
+    if (session_id == VOICE_VSID) {
+        out->usecase = USECASE_INCALL_MUSIC_UPLINK;
+    } else if (session_id == VOICE2_VSID) {
+        out->usecase = USECASE_INCALL_MUSIC_UPLINK2;
+    } else {
+        ALOGE("%s: Invalid session id %x", __func__, session_id);
+        return -EINVAL;
+    }
+
+    out->config = pcm_config_incall_music;
+    out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_MONO;
+    out->channel_mask = AUDIO_CHANNEL_OUT_MONO;
+
+    return 0;
+}
+
diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h
index 568f716..a8efef1 100644
--- a/hal/voice_extn/voice_extn.h
+++ b/hal/voice_extn/voice_extn.h
@@ -20,6 +20,7 @@
 #ifndef VOICE_EXTN_H
 #define VOICE_EXTN_H
 
+#ifdef MULTI_VOICE_SESSION_ENABLED
 int voice_extn_update_calls(struct audio_device *adev);
 int voice_extn_get_session_from_use_case(struct audio_device *adev,
                                          const audio_usecase_t usecase_id,
@@ -30,37 +31,48 @@
 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)
+#else
+static int voice_extn_update_calls(struct audio_device *adev)
 {
     return -ENOSYS;
 }
 
-int voice_extn_get_session_from_use_case(struct audio_device *adev,
-                                       const audio_usecase_t usecase_id,
-                                       struct voice_session **session)
+static int voice_extn_get_session_from_use_case(struct audio_device *adev,
+                                                const audio_usecase_t usecase_id,
+                                                struct voice_session **session)
 {
     return -ENOSYS;
 }
 
-int voice_extn_init(struct audio_device *adev)
+static int voice_extn_init(struct audio_device *adev)
 {
     return -ENOSYS;
 }
 
-int  voice_extn_set_parameters(struct audio_device *adev,
-                               struct str_parms *parms)
+static int voice_extn_set_parameters(struct audio_device *adev,
+                                     struct str_parms *parms)
 {
     return -ENOSYS;
 }
 
-int voice_extn_is_in_call(struct audio_device *adev, bool *in_call)
+static int voice_extn_is_in_call(struct audio_device *adev, bool *in_call)
 {
     return -ENOSYS;
 }
-int voice_extn_get_active_session_id(struct audio_device *adev,
-                                     uint32_t *session_id)
+
+static int voice_extn_get_active_session_id(struct audio_device *adev,
+                                            uint32_t *session_id)
+{
+    return -ENOSYS;
+}
+#endif
+
+#if defined INCALL_MUSIC_ENABLED && defined MULTI_VOICE_SESSION_ENABLED
+int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev,
+                                                  struct stream_out *out);
+#else
+static int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev,
+                                                         struct stream_out *out)
 {
     return -ENOSYS;
 }