Snap for 5130385 from c4de160ac82905147883b15577091fa99c5530a4 to pi-qpr2-release

Change-Id: I605dd5369373b708036e708e0941a843a5e18e1c
diff --git a/hal/Android.mk b/hal/Android.mk
index b73038a..236ed11 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -207,6 +207,10 @@
     LOCAL_SRC_FILES += audio_extn/maxxaudio.c
 endif
 
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_24BITS_CAMCORDER)), true)
+    LOCAL_CFLAGS += -DENABLED_24BITS_CAMCORDER
+endif
+
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_BG_CAL)),true)
     LOCAL_CFLAGS += -DBG_CODEC_CAL
 endif
diff --git a/hal/audio_extn/maxxaudio.c b/hal/audio_extn/maxxaudio.c
index fc65332..2fd188d 100644
--- a/hal/audio_extn/maxxaudio.c
+++ b/hal/audio_extn/maxxaudio.c
@@ -41,29 +41,40 @@
 #define CAL_PRESIST_STR "cal_persist"
 #define CAL_SAMPLERATE_STR "cal_samplerate"
 
-#define MA_QDSP_PARAM_INIT "maxxaudio_qdsp_initialize"
-#define MA_QDSP_PARAM_DEINIT "maxxaudio_qdsp_uninitialize"
-#define MA_QDSP_SET_LR_SWAP "maxxaudio_qdsp_set_lr_swap"
-#define MA_QDSP_SET_MODE "maxxaudio_qdsp_set_sound_mode"
-#define MA_QDSP_SET_VOL "maxxaudio_qdsp_set_volume"
-#define MA_QDSP_SET_VOLT "maxxaudio_qdsp_set_volume_table"
+#define MA_QDSP_PARAM_INIT      "maxxaudio_qdsp_initialize"
+#define MA_QDSP_PARAM_DEINIT    "maxxaudio_qdsp_uninitialize"
+#define MA_QDSP_SET_LR_SWAP     "maxxaudio_qdsp_set_lr_swap"
+#define MA_QDSP_SET_MODE        "maxxaudio_qdsp_set_sound_mode"
+#define MA_QDSP_SET_VOL         "maxxaudio_qdsp_set_volume"
+#define MA_QDSP_SET_VOLT        "maxxaudio_qdsp_set_volume_table"
+#define MA_QDSP_SET_PARAM       "maxxaudio_qdsp_set_parameter"
 
 #define SUPPORT_DEV "Blackbird"
 #define SUPPORTED_USB 0x01
 
-struct ma_audio_cal_settings {
-    int app_type;
-    audio_devices_t device;
-};
+typedef unsigned int effective_scope_flag_t;
+const effective_scope_flag_t EFFECTIVE_SCOPE_RTC = 1 << 0;   /* RTC  */
+const effective_scope_flag_t EFFECTIVE_SCOPE_ACDB = 1 << 1;  /* ACDB */
+const effective_scope_flag_t EFFECTIVE_SCOPE_ALL = EFFECTIVE_SCOPE_RTC | EFFECTIVE_SCOPE_ACDB;
+const effective_scope_flag_t EFFECTIVE_SCOPE_NONE = 0;
+const effective_scope_flag_t EFFECTIVE_SCOPE_DEFAULT = EFFECTIVE_SCOPE_NONE;
 
-struct ma_state {
-    float vol;
-    bool active;
-};
+const unsigned int AUDIO_CAL_SETTINGS_VERSION_MAJOR = 2;
+const unsigned int AUDIO_CAL_SETTINGS_VERSION_MINOR = 0;
+const unsigned int AUDIO_CAL_SETTINGS_VERSION_MAJOR_DEFAULT = AUDIO_CAL_SETTINGS_VERSION_MAJOR;
+const unsigned int AUDIO_CAL_SETTINGS_VERSION_MINOR_DEFAULT = AUDIO_CAL_SETTINGS_VERSION_MINOR;
+
+const unsigned int VALUE_AUTO = 0xFFFFFFFF;
+const unsigned int APP_TYPE_AUTO = VALUE_AUTO;
+const unsigned int APP_TYPE_DEFAULT = APP_TYPE_AUTO;
+const unsigned int DEVICE_AUTO = VALUE_AUTO;
+const unsigned int DEVICE_DEFAULT = DEVICE_AUTO;
+
+const unsigned int MAAP_OUTPUT_GAIN = 27;
 
 typedef enum MA_STREAM_TYPE {
-    STREAM_MIN_STREAM_TYPES,
-    STREAM_VOICE = STREAM_MIN_STREAM_TYPES,
+    STREAM_MIN_TYPES = 0,
+    STREAM_VOICE = STREAM_MIN_TYPES,
     STREAM_SYSTEM,
     STREAM_RING,
     STREAM_MUSIC,
@@ -76,8 +87,31 @@
     MA_CMD_VOL,
     MA_CMD_SWAP_ENABLE,
     MA_CMD_SWAP_DISABLE,
+    MA_CMD_SOFT_MUTE_ENABLE,
+    MA_CMD_SOFT_MUTE_DISABLE,
 } ma_cmd_t;
 
+typedef struct ma_audio_cal_version {
+    unsigned int major;
+    unsigned int minor;
+} ma_audio_cal_version_t;
+
+typedef struct ma_audio_cal_common_settings {
+    unsigned int app_type;
+    unsigned int device;
+} ma_audio_cal_common_settings_t;
+
+struct ma_audio_cal_settings {
+    ma_audio_cal_version_t version;
+    ma_audio_cal_common_settings_t common;
+    effective_scope_flag_t effect_scope_flag;
+};
+
+struct ma_state {
+    float vol;
+    bool active;
+};
+
 typedef void *ma_audio_cal_handle_t;
 typedef int (*set_audio_cal_t)(const char *);
 
@@ -100,6 +134,10 @@
                                       const struct ma_audio_cal_settings *,
                                       size_t, struct ma_state *);
 
+typedef bool (*ma_set_param_t)(ma_audio_cal_handle_t,
+                               const struct ma_audio_cal_settings *,
+                               unsigned int, double);
+
 struct ma_platform_data {
     void *waves_handle;
     void *platform;
@@ -110,6 +148,7 @@
     ma_set_sound_mode_t      ma_set_sound_mode;
     ma_set_volume_t          ma_set_volume;
     ma_set_volume_table_t    ma_set_volume_table;
+    ma_set_param_t           ma_set_param;
 };
 
 ma_audio_cal_handle_t g_ma_audio_cal_handle = NULL;
@@ -155,6 +194,14 @@
                                         volume_table);
 }
 
+static bool ma_set_param_l(
+    const struct ma_audio_cal_settings *audio_cal_settings,
+    unsigned int index, double value)
+{
+    return my_data->ma_set_param(g_ma_audio_cal_handle,
+                                 audio_cal_settings, index, value);
+}
+
 static inline bool valid_usecase(struct audio_usecase *usecase)
 {
     if ((usecase->type == PCM_PLAYBACK) &&
@@ -164,9 +211,8 @@
          (usecase->id == USECASE_AUDIO_PLAYBACK_OFFLOAD)) &&
         /* support devices */
         ((usecase->devices & AUDIO_DEVICE_OUT_SPEAKER) ||
-         (usecase->devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE) ||
-         /* TODO: enable A2DP when it is ready */
-         (usecase->devices & AUDIO_DEVICE_OUT_ALL_USB)))
+         (usecase->devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE)))
+         /* TODO: enable A2DP/USB when it is ready */
 
         return true;
 
@@ -182,13 +228,21 @@
     ma_stream_type_t i = 0;
 
     for (i = 0; i < STREAM_MAX_TYPES; i++)
-        if (ma_cur_state_table[i].active &&
-                (ma_cur_state_table[i].vol != 0))
+        if (ma_cur_state_table[i].active)
             return true;
 
     return false;
 }
 
+static void ma_cal_init(struct ma_audio_cal_settings *ma_cal)
+{
+    ma_cal->version.major = AUDIO_CAL_SETTINGS_VERSION_MAJOR_DEFAULT;
+    ma_cal->version.minor = AUDIO_CAL_SETTINGS_VERSION_MINOR_DEFAULT;
+    ma_cal->common.app_type = APP_TYPE_DEFAULT;
+    ma_cal->common.device = DEVICE_DEFAULT;
+    ma_cal->effect_scope_flag = EFFECTIVE_SCOPE_ALL;
+}
+
 static bool check_and_send_all_audio_cal(struct audio_device *adev, ma_cmd_t cmd)
 {
     int i = 0;
@@ -196,32 +250,27 @@
     float vol = 0;
     struct listnode *node;
     struct audio_usecase *usecase;
-    struct ma_audio_cal_settings *ma_cal = NULL;
+    struct ma_audio_cal_settings ma_cal;
 
-    // alloct
-    ma_cal = (struct ma_audio_cal_settings *)malloc(sizeof(struct ma_audio_cal_settings));
-
-    if (ma_cal == NULL) {
-        ALOGE("%s: ma_cal alloct fail", __func__);
-        return ret;
-    }
+    ma_cal_init(&ma_cal);
 
     list_for_each(node, &adev->usecase_list) {
         usecase = node_to_item(node, struct audio_usecase, list);
         if (valid_usecase(usecase)) {
-            ma_cal->app_type = usecase->stream.out->app_type_cfg.app_type;
-            ma_cal->device = usecase->stream.out->devices;
+            ma_cal.common.app_type = usecase->stream.out->app_type_cfg.app_type;
+            ma_cal.common.device = usecase->stream.out->devices;
             ALOGV("%s: send usecase(%d) app_type(%d) device(%d)",
-                      __func__, usecase->id, ma_cal->app_type, ma_cal->device);
+                      __func__, usecase->id, ma_cal.common.app_type,
+                      ma_cal.common.device);
 
             switch (cmd) {
                 case MA_CMD_VOL:
-                    ret = ma_set_volume_table_l(ma_cal, STREAM_MAX_TYPES,
+                    ret = ma_set_volume_table_l(&ma_cal, STREAM_MAX_TYPES,
                                                 ma_cur_state_table);
                     if (ret)
-                        ALOGV("Waves: ma_set_volume_table_l success");
+                        ALOGV("ma_set_volume_table_l success");
                     else
-                        ALOGE("Waves: ma_set_volume_table_l %f returned with error.", vol);
+                        ALOGE("ma_set_volume_table_l returned with error.");
 
                     ALOGV("%s: send volume table === Start", __func__);
                     for (i = 0; i < STREAM_MAX_TYPES; i++)
@@ -230,26 +279,46 @@
                               ma_cur_state_table[i].active ? "T" : "F");
                     ALOGV("%s: send volume table === End", __func__);
                     break;
+
                 case MA_CMD_SWAP_ENABLE:
-                    ret = ma_set_lr_swap_l(ma_cal, true);
+                    ret = ma_set_lr_swap_l(&ma_cal, true);
                     if (ret)
-                        ALOGV("Waves: ma_set_lr_swap_l enable returned with success.");
+                        ALOGV("ma_set_lr_swap_l enable returned with success.");
                     else
-                        ALOGE("Waves: ma_set_lr_swap_l enable returned with error.");
+                        ALOGE("ma_set_lr_swap_l enable returned with error.");
                     break;
+
                 case MA_CMD_SWAP_DISABLE:
-                    ret = ma_set_lr_swap_l(ma_cal, false);
+                    ret = ma_set_lr_swap_l(&ma_cal, false);
                     if (ret)
-                        ALOGV("Waves: ma_set_lr_swap_l disable returned with success.");
+                        ALOGV("ma_set_lr_swap_l disable returned with success.");
                     else
-                        ALOGE("Waves: ma_set_lr_swap_l disable returned with error.");
+                        ALOGE("ma_set_lr_swap_l disable returned with error.");
                     break;
+
+                case MA_CMD_SOFT_MUTE_ENABLE:
+                    if (usecase->id == USECASE_AUDIO_PLAYBACK_LOW_LATENCY) break;
+
+                    ma_cal.effect_scope_flag = EFFECTIVE_SCOPE_RTC;
+                    ret = ma_set_param_l(&ma_cal, MAAP_OUTPUT_GAIN, -96);
+                    if (!ret)
+                        ALOGE("soft mute enable returned with error.");
+                    break;
+
+                case MA_CMD_SOFT_MUTE_DISABLE:
+                    if (usecase->id == USECASE_AUDIO_PLAYBACK_LOW_LATENCY) break;
+
+                    ma_cal.effect_scope_flag = EFFECTIVE_SCOPE_RTC;
+                    ret = ma_set_param_l(&ma_cal, MAAP_OUTPUT_GAIN, 0);
+                    if (!ret)
+                        ALOGE("soft mute disable returned with error.");
+                    break;
+
                 default:
                     ALOGE("%s: unsupported cmd %d", __func__, cmd);
             }
         }
     }
-    free(ma_cal);
 
     return ret;
 }
@@ -417,6 +486,13 @@
              ALOGE("%s: dlsym error %s for ma_set_volume_table", __func__, dlerror());
              goto error;
          }
+
+         my_data->ma_set_param = (ma_set_param_t)dlsym(
+                                  my_data->waves_handle, MA_QDSP_SET_PARAM);
+         if (!my_data->ma_set_param) {
+             ALOGE("%s: dlsym error %s for ma_set_param", __func__, dlerror());
+             goto error;
+         }
     }
 
     /* get preset table */
@@ -509,27 +585,42 @@
                              float vol, bool active)
 {
     bool ret = false;
-    ma_stream_type_t stype = (ma_stream_type_t)stream_type;
+    bool first_enable = false;
+    struct ma_state pr_mstate;
 
-    ALOGV("%s: stream[%d] vol[%f] active[%s]",
-          __func__, stream_type, vol, active ? "true" : "false");
+    if (stream_type >= STREAM_MAX_TYPES ||
+        stream_type < STREAM_MIN_TYPES) {
+        ALOGE("%s: stream_type %d out of range.", __func__, stream_type);
+        return ret;
+    }
 
     if (!my_data) {
         ALOGV("%s: maxxaudio isn't initialized.", __func__);
         return ret;
     }
 
-    // update condition
-    // 1. start track: active and volume isn't zero
-    // 2. stop track: no tracks are active
-    if ((active && vol != 0) ||
-        (!active)) {
-        pthread_mutex_lock(&my_data->lock);
+    ALOGV("%s: stream[%d] vol[%f] active[%s]",
+          __func__, stream_type, vol, active ? "true" : "false");
 
-        ma_cur_state_table[stype].vol = vol;
-        ma_cur_state_table[stype].active = active;
-        if (is_active())
-            ret = check_and_send_all_audio_cal(adev, MA_CMD_VOL);
+    pr_mstate.vol = ma_cur_state_table[(ma_stream_type_t)stream_type].vol;
+    pr_mstate.active = ma_cur_state_table[(ma_stream_type_t)stream_type].active;
+
+    // update condition: vol or active state changes
+    if (pr_mstate.vol != vol || pr_mstate.active != active) {
+
+        pthread_mutex_lock(&my_data->lock);
+        // get active state before updating
+        first_enable = (!is_active()) && active;
+
+        ma_cur_state_table[(ma_stream_type_t)stream_type].vol = vol;
+        ma_cur_state_table[(ma_stream_type_t)stream_type].active = active;
+
+        if (first_enable) //all F -> one of T
+            ret = check_and_send_all_audio_cal(adev, MA_CMD_SOFT_MUTE_DISABLE);
+        else if (!is_active()) // all F
+            ret = check_and_send_all_audio_cal(adev, MA_CMD_SOFT_MUTE_ENABLE);
+
+        ret = check_and_send_all_audio_cal(adev, MA_CMD_VOL);
 
         pthread_mutex_unlock(&my_data->lock);
     }
@@ -542,7 +633,7 @@
     int i = 0;
     int u_index = -1;
     float vol = 0;
-    struct ma_audio_cal_settings *ma_cal = NULL;
+    struct ma_audio_cal_settings ma_cal;
 
     if (!my_data) {
         ALOGV("%s: maxxaudio isn't initialized.", __func__);
@@ -554,38 +645,34 @@
         return;
     }
 
-    ma_cal = (struct ma_audio_cal_settings *)malloc(sizeof(struct ma_audio_cal_settings));
+    ma_cal_init(&ma_cal);
 
     /* update audio_cal and send it */
-    if (ma_cal != NULL){
-        ma_cal->app_type = usecase->stream.out->app_type_cfg.app_type;
-        ma_cal->device = usecase->stream.out->devices;
-        ALOGV("%s: send usecase(%d) app_type(%d) device(%d)",
-                      __func__, usecase->id, ma_cal->app_type, ma_cal->device);
+    ma_cal.common.app_type = usecase->stream.out->app_type_cfg.app_type;
+    ma_cal.common.device = usecase->stream.out->devices;
+    ALOGV("%s: send usecase(%d) app_type(%d) device(%d)",
+              __func__, usecase->id, ma_cal.common.app_type,
+              ma_cal.common.device);
 
-        pthread_mutex_lock(&my_data->lock);
+    pthread_mutex_lock(&my_data->lock);
 
-        if (is_active()) {
-            ALOGV("%s: send volume table === Start", __func__);
-            for (i = 0; i < STREAM_MAX_TYPES; i++)
-                ALOGV("%s: stream(%d) volume(%f) active(%s)", __func__, i,
-                    ma_cur_state_table[i].vol,
-                    ma_cur_state_table[i].active ? "T" : "F");
-            ALOGV("%s: send volume table === End", __func__);
+    if (is_active()) {
+        ALOGV("%s: send volume table === Start", __func__);
+        for (i = 0; i < STREAM_MAX_TYPES; i++)
+            ALOGV("%s: stream(%d) volume(%f) active(%s)", __func__, i,
+                   ma_cur_state_table[i].vol,
+                   ma_cur_state_table[i].active ? "T" : "F");
+        ALOGV("%s: send volume table === End", __func__);
 
-            if (!ma_set_volume_table_l(ma_cal,
-                                       STREAM_MAX_TYPES,
-                                       ma_cur_state_table))
-                ALOGE("Waves: ma_set_volume_table_l %f returned with error.", vol);
-            else
-                ALOGV("Waves: ma_set_volume_table_l success");
+        if (!ma_set_volume_table_l(&ma_cal,
+                                   STREAM_MAX_TYPES,
+                                   ma_cur_state_table))
+            ALOGE("ma_set_volume_table_l returned with error.");
+        else
+            ALOGV("ma_set_volume_table_l success");
 
-        }
-        pthread_mutex_unlock(&my_data->lock);
-        free(ma_cal);
-    } else {
-        ALOGE("%s: ma_cal alloct fail", __func__);
     }
+    pthread_mutex_unlock(&my_data->lock);
 }
 
 void audio_extn_ma_set_parameters(struct audio_device *adev,
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 9559573..8e04bf8 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -540,6 +540,20 @@
     return false;
 }
 
+static bool is_supported_24bits_audiosource(audio_source_t source)
+{
+    switch (source) {
+        case AUDIO_SOURCE_UNPROCESSED:
+#ifdef ENABLED_24BITS_CAMCORDER
+        case AUDIO_SOURCE_CAMCORDER:
+#endif
+            return true;
+        default:
+            break;
+    }
+    return false;
+}
+
 static inline bool is_mmap_usecase(audio_usecase_t uc_id)
 {
     return (uc_id == USECASE_AUDIO_RECORD_AFE_PROXY) ||
@@ -4703,20 +4717,24 @@
             adev->screen_off = true;
     }
 
-#ifndef MAXXAUDIO_QDSP_ENABLED
     ret = str_parms_get_int(parms, "rotation", &val);
     if (ret >= 0) {
         bool reverse_speakers = false;
+        int camera_rotation = CAMERA_ROTATION_LANDSCAPE;
         switch (val) {
         // FIXME: note that the code below assumes that the speakers are in the correct placement
         //   relative to the user when the device is rotated 90deg from its default rotation. This
         //   assumption is device-specific, not platform-specific like this code.
         case 270:
             reverse_speakers = true;
+            camera_rotation = CAMERA_ROTATION_INVERT_LANDSCAPE;
             break;
         case 0:
-        case 90:
         case 180:
+            camera_rotation = CAMERA_ROTATION_PORTRAIT;
+            break;
+        case 90:
+            camera_rotation = CAMERA_ROTATION_LANDSCAPE;
             break;
         default:
             ALOGE("%s: unexpected rotation of %d", __func__, val);
@@ -4726,10 +4744,13 @@
             // check and set swap
             //   - check if orientation changed and speaker active
             //   - set rotation and cache the rotation value
+            adev->camera_orientation =
+                           (adev->camera_orientation & ~CAMERA_ROTATION_MASK) | camera_rotation;
+#ifndef MAXXAUDIO_QDSP_ENABLED
             platform_check_and_set_swap_lr_channels(adev, reverse_speakers);
+#endif
         }
     }
-#endif
 
     ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_SCO_WB, value, sizeof(value));
     if (ret >= 0) {
@@ -4798,6 +4819,32 @@
         }
     }
 
+    //FIXME: to be replaced by proper video capture properties API
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_CAMERA_FACING, value, sizeof(value));
+    if (ret >= 0) {
+        int camera_facing = CAMERA_FACING_BACK;
+        if (strcmp(value, AUDIO_PARAMETER_VALUE_FRONT) == 0)
+            camera_facing = CAMERA_FACING_FRONT;
+        else if (strcmp(value, AUDIO_PARAMETER_VALUE_BACK) == 0)
+            camera_facing = CAMERA_FACING_BACK;
+        else {
+            ALOGW("%s: invalid camera facing value: %s", __func__, value);
+            goto done;
+        }
+        adev->camera_orientation =
+                       (adev->camera_orientation & ~CAMERA_FACING_MASK) | camera_facing;
+        struct audio_usecase *usecase;
+        struct listnode *node;
+        list_for_each(node, &adev->usecase_list) {
+            usecase = node_to_item(node, struct audio_usecase, list);
+            struct stream_in *in = usecase->stream.in;
+            if (usecase->type == PCM_CAPTURE && in != NULL &&
+                    in->source == AUDIO_SOURCE_CAMCORDER && !in->standby) {
+                select_devices(adev, in->usecase);
+            }
+        }
+    }
+
 done:
     str_parms_destroy(parms);
     pthread_mutex_unlock(&adev->lock);
@@ -5083,7 +5130,7 @@
 
            on error flinger will retry with supported format passed
          */
-        if (source != AUDIO_SOURCE_UNPROCESSED) {
+        if (!is_supported_24bits_audiosource(source)) {
             config->format = AUDIO_FORMAT_PCM_16_BIT;
             ret_error = true;
         } else if (config->format != AUDIO_FORMAT_PCM_8_24_BIT) {
@@ -5706,6 +5753,8 @@
 
     adev->mic_break_enabled = property_get_bool("vendor.audio.mic_break", false);
 
+    adev->camera_orientation = CAMERA_DEFAULT;
+
     // commented as full set of app type cfg is sent from platform
     // audio_extn_utils_send_default_app_type_cfg(adev->platform, adev->mixer);
     audio_device_ref_count++;
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 6379844..0b3b028 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -159,6 +159,33 @@
     OFFLOAD_CMD_ERROR,              /* offload playback hit some error */
 };
 
+/*
+ * Camera selection indicated via set_parameters "cameraFacing=front|back and
+ * "rotation=0|90|180|270""
+ */
+enum {
+  CAMERA_FACING_BACK = 0x0,
+  CAMERA_FACING_FRONT = 0x1,
+  CAMERA_FACING_MASK = 0x0F,
+  CAMERA_ROTATION_LANDSCAPE = 0x0,
+  CAMERA_ROTATION_INVERT_LANDSCAPE = 0x10,
+  CAMERA_ROTATION_PORTRAIT = 0x20,
+  CAMERA_ROTATION_MASK = 0xF0,
+  CAMERA_BACK_LANDSCAPE = (CAMERA_FACING_BACK|CAMERA_ROTATION_LANDSCAPE),
+  CAMERA_BACK_INVERT_LANDSCAPE = (CAMERA_FACING_BACK|CAMERA_ROTATION_INVERT_LANDSCAPE),
+  CAMERA_BACK_PORTRAIT = (CAMERA_FACING_BACK|CAMERA_ROTATION_PORTRAIT),
+  CAMERA_FRONT_LANDSCAPE = (CAMERA_FACING_FRONT|CAMERA_ROTATION_LANDSCAPE),
+  CAMERA_FRONT_INVERT_LANDSCAPE = (CAMERA_FACING_FRONT|CAMERA_ROTATION_INVERT_LANDSCAPE),
+  CAMERA_FRONT_PORTRAIT = (CAMERA_FACING_FRONT|CAMERA_ROTATION_PORTRAIT),
+
+  CAMERA_DEFAULT = CAMERA_BACK_LANDSCAPE,
+};
+
+//FIXME: to be replaced by proper video capture properties API
+#define AUDIO_PARAMETER_KEY_CAMERA_FACING "cameraFacing"
+#define AUDIO_PARAMETER_VALUE_FRONT "front"
+#define AUDIO_PARAMETER_VALUE_BACK "back"
+
 enum {
     OFFLOAD_STATE_IDLE,
     OFFLOAD_STATE_PLAYING,
@@ -309,6 +336,7 @@
 
 struct audio_device {
     struct audio_hw_device device;
+
     pthread_mutex_t lock; /* see note below on mutex acquisition order */
     struct mixer *mixer;
     audio_mode_t mode;
@@ -367,6 +395,7 @@
 
     /* logging */
     snd_device_t last_logged_snd_device[AUDIO_USECASE_MAX][2]; /* [out, in] */
+    int camera_orientation; /* CAMERA_BACK_LANDSCAPE ... CAMERA_FRONT_PORTRAIT */
 };
 
 int select_devices(struct audio_device *adev,
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 7563689..5a36f0c 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -317,7 +317,7 @@
     [SND_DEVICE_IN_BT_SCO_MIC_NREC] = "bt-sco-mic",
     [SND_DEVICE_IN_BT_SCO_MIC_WB] = "bt-sco-mic-wb",
     [SND_DEVICE_IN_BT_SCO_MIC_WB_NREC] = "bt-sco-mic-wb",
-    [SND_DEVICE_IN_CAMCORDER_MIC] = "camcorder-mic",
+    [SND_DEVICE_IN_CAMCORDER_LANDSCAPE] = "camcorder-mic",
 
     [SND_DEVICE_IN_VOICE_DMIC] = "voice-dmic-ef",
     [SND_DEVICE_IN_VOICE_DMIC_TMUS] = "voice-dmic-ef-tmus",
@@ -359,6 +359,11 @@
     [SND_DEVICE_IN_HANDSET_QMIC] = "quad-mic",
     [SND_DEVICE_IN_HANDSET_TMIC_AEC] = "three-mic",
     [SND_DEVICE_IN_HANDSET_QMIC_AEC] = "quad-mic",
+    [SND_DEVICE_IN_CAMCORDER_INVERT_LANDSCAPE] = "camcorder-mic",
+    [SND_DEVICE_IN_CAMCORDER_PORTRAIT] = "camcorder-mic",
+    [SND_DEVICE_IN_CAMCORDER_SELFIE_LANDSCAPE] = "camcorder-mic",
+    [SND_DEVICE_IN_CAMCORDER_SELFIE_INVERT_LANDSCAPE] = "camcorder-mic",
+    [SND_DEVICE_IN_CAMCORDER_SELFIE_PORTRAIT] = "camcorder-mic",
 };
 
 /* ACDB IDs (audio DSP path configuration IDs) for each sound device */
@@ -436,7 +441,7 @@
     [SND_DEVICE_IN_BT_SCO_MIC_NREC] = 21,
     [SND_DEVICE_IN_BT_SCO_MIC_WB] = 38,
     [SND_DEVICE_IN_BT_SCO_MIC_WB_NREC] = 38,
-    [SND_DEVICE_IN_CAMCORDER_MIC] = 61,
+    [SND_DEVICE_IN_CAMCORDER_LANDSCAPE] = 61,
 
     [SND_DEVICE_IN_VOICE_DMIC] = 41,
     [SND_DEVICE_IN_VOICE_DMIC_TMUS] = ACDB_ID_VOICE_DMIC_EF_TMUS,
@@ -477,6 +482,11 @@
     [SND_DEVICE_IN_HANDSET_QMIC] = 125,
     [SND_DEVICE_IN_HANDSET_TMIC_AEC] = 125, /* override this for new target to 140 */
     [SND_DEVICE_IN_HANDSET_QMIC_AEC] = 125, /* override this for new target to 140 */
+    [SND_DEVICE_IN_CAMCORDER_INVERT_LANDSCAPE] = 61,
+    [SND_DEVICE_IN_CAMCORDER_PORTRAIT] = 61,
+    [SND_DEVICE_IN_CAMCORDER_SELFIE_LANDSCAPE] = 61,
+    [SND_DEVICE_IN_CAMCORDER_SELFIE_INVERT_LANDSCAPE] = 61,
+    [SND_DEVICE_IN_CAMCORDER_SELFIE_PORTRAIT] = 61,
 };
 
 // Platform specific backend bit width table
@@ -565,7 +575,7 @@
     {TO_NAME_INDEX(SND_DEVICE_IN_BT_SCO_MIC_NREC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_BT_SCO_MIC_WB)},
     {TO_NAME_INDEX(SND_DEVICE_IN_BT_SCO_MIC_WB_NREC)},
-    {TO_NAME_INDEX(SND_DEVICE_IN_CAMCORDER_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_CAMCORDER_LANDSCAPE)},
 
     {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_DMIC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_DMIC_TMUS)},
@@ -606,6 +616,13 @@
     {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_QMIC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_TMIC_AEC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_QMIC_AEC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_CAMCORDER_INVERT_LANDSCAPE)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_CAMCORDER_PORTRAIT)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_CAMCORDER_SELFIE_LANDSCAPE)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_CAMCORDER_SELFIE_INVERT_LANDSCAPE)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_CAMCORDER_SELFIE_PORTRAIT)},
+    /* For legacy xml file parsing */
+    {TO_NAME_INDEX(SND_DEVICE_IN_CAMCORDER_MIC)},
 };
 
 static char * backend_tag_table[SND_DEVICE_MAX] = {0};
@@ -1296,7 +1313,7 @@
     hw_interface_table[SND_DEVICE_IN_HANDSET_DMIC_STEREO] = strdup("SLIMBUS_0_TX");
     hw_interface_table[SND_DEVICE_IN_HEADSET_MIC] = strdup("SLIMBUS_0_TX");
     hw_interface_table[SND_DEVICE_IN_HEADSET_MIC_AEC] = strdup("SLIMBUS_0_TX");
-    hw_interface_table[SND_DEVICE_IN_CAMCORDER_MIC] = strdup("SLIMBUS_0_TX");
+    hw_interface_table[SND_DEVICE_IN_CAMCORDER_LANDSCAPE] = strdup("SLIMBUS_0_TX");
     hw_interface_table[SND_DEVICE_IN_VOICE_REC_MIC] = strdup("SLIMBUS_0_TX");
     hw_interface_table[SND_DEVICE_IN_VOICE_REC_MIC_NS] = strdup("SLIMBUS_0_TX");
     hw_interface_table[SND_DEVICE_IN_VOICE_REC_MIC_AEC] = strdup("SLIMBUS_0_TX");
@@ -1338,6 +1355,11 @@
     hw_interface_table[SND_DEVICE_IN_HANDSET_QMIC] = strdup("SLIMBUS_0_TX");
     hw_interface_table[SND_DEVICE_IN_HANDSET_TMIC_AEC] = strdup("SLIMBUS_0_TX");
     hw_interface_table[SND_DEVICE_IN_HANDSET_QMIC_AEC] = strdup("SLIMBUS_0_TX");
+    hw_interface_table[SND_DEVICE_IN_CAMCORDER_INVERT_LANDSCAPE] = strdup("SLIMBUS_0_TX");
+    hw_interface_table[SND_DEVICE_IN_CAMCORDER_PORTRAIT] = strdup("SLIMBUS_0_TX");
+    hw_interface_table[SND_DEVICE_IN_CAMCORDER_SELFIE_LANDSCAPE] = strdup("SLIMBUS_0_TX");
+    hw_interface_table[SND_DEVICE_IN_CAMCORDER_SELFIE_INVERT_LANDSCAPE] = strdup("SLIMBUS_0_TX");
+    hw_interface_table[SND_DEVICE_IN_CAMCORDER_SELFIE_PORTRAIT] = strdup("SLIMBUS_0_TX");
     my_data->max_mic_count = PLATFORM_DEFAULT_MIC_COUNT;
 }
 
@@ -2952,7 +2974,30 @@
     } else if (source == AUDIO_SOURCE_CAMCORDER) {
         if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC ||
             in_device & AUDIO_DEVICE_IN_BACK_MIC) {
-            snd_device = SND_DEVICE_IN_CAMCORDER_MIC;
+            switch (adev->camera_orientation) {
+            case CAMERA_BACK_LANDSCAPE:
+                snd_device = SND_DEVICE_IN_CAMCORDER_LANDSCAPE;
+                break;
+            case CAMERA_BACK_INVERT_LANDSCAPE:
+                snd_device = SND_DEVICE_IN_CAMCORDER_INVERT_LANDSCAPE;
+                break;
+            case CAMERA_BACK_PORTRAIT:
+                snd_device = SND_DEVICE_IN_CAMCORDER_PORTRAIT;
+                break;
+            case CAMERA_FRONT_LANDSCAPE:
+                snd_device = SND_DEVICE_IN_CAMCORDER_SELFIE_LANDSCAPE;
+                break;
+            case CAMERA_FRONT_INVERT_LANDSCAPE:
+                snd_device = SND_DEVICE_IN_CAMCORDER_SELFIE_INVERT_LANDSCAPE;
+                break;
+            case CAMERA_FRONT_PORTRAIT:
+                snd_device = SND_DEVICE_IN_CAMCORDER_SELFIE_PORTRAIT;
+                break;
+            default:
+                ALOGW("%s: invalid camera orientation %08x", __func__, adev->camera_orientation);
+                snd_device = SND_DEVICE_IN_CAMCORDER_LANDSCAPE;
+                break;
+            }
         }
     } else if (source == AUDIO_SOURCE_VOICE_RECOGNITION) {
         if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 2a9646c..f6c5a58 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -142,7 +142,7 @@
     SND_DEVICE_IN_BT_SCO_MIC_NREC,
     SND_DEVICE_IN_BT_SCO_MIC_WB,
     SND_DEVICE_IN_BT_SCO_MIC_WB_NREC,
-    SND_DEVICE_IN_CAMCORDER_MIC,
+    SND_DEVICE_IN_CAMCORDER_LANDSCAPE,
 
     SND_DEVICE_IN_VOICE_DMIC,
     SND_DEVICE_IN_VOICE_DMIC_TMUS,
@@ -185,10 +185,16 @@
     SND_DEVICE_IN_HANDSET_QMIC,
     SND_DEVICE_IN_HANDSET_TMIC_AEC,
     SND_DEVICE_IN_HANDSET_QMIC_AEC,
+    SND_DEVICE_IN_CAMCORDER_INVERT_LANDSCAPE,
+    SND_DEVICE_IN_CAMCORDER_PORTRAIT,
+    SND_DEVICE_IN_CAMCORDER_SELFIE_LANDSCAPE,
+    SND_DEVICE_IN_CAMCORDER_SELFIE_INVERT_LANDSCAPE,
+    SND_DEVICE_IN_CAMCORDER_SELFIE_PORTRAIT,
     SND_DEVICE_IN_END,
 
     SND_DEVICE_MAX = SND_DEVICE_IN_END,
-
+    /* For legacy xml file parsing */
+    SND_DEVICE_IN_CAMCORDER_MIC = SND_DEVICE_IN_CAMCORDER_LANDSCAPE,
 };
 #define DEFAULT_OUTPUT_SAMPLING_RATE    48000
 #define OUTPUT_SAMPLING_RATE_44100      44100