QC audio HAL handles device rotation

Use the "speaker-reverse" configuration when the device rotation
 requires it. Device rotation is received through a parameter to
 parse.

Bug 9095903

Change-Id: Ie24a625a18e1fc1093f6f564ba0ff0f5cbb5cce0
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index c874aa8..7eef1f7 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -87,6 +87,7 @@
     /* Playback sound devices */
     [SND_DEVICE_OUT_HANDSET] = "handset",
     [SND_DEVICE_OUT_SPEAKER] = "speaker",
+    [SND_DEVICE_OUT_SPEAKER_REVERSE] = "speaker-reverse",
     [SND_DEVICE_OUT_HEADPHONES] = "headphones",
     [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = "speaker-and-headphones",
     [SND_DEVICE_OUT_VOICE_SPEAKER] = "voice-speaker",
@@ -131,6 +132,7 @@
     [SND_DEVICE_NONE] = -1,
     [SND_DEVICE_OUT_HANDSET] = 7,
     [SND_DEVICE_OUT_SPEAKER] = 14,
+    [SND_DEVICE_OUT_SPEAKER_REVERSE] = 14,
     [SND_DEVICE_OUT_HEADPHONES] = 10,
     [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = 10,
     [SND_DEVICE_OUT_VOICE_SPEAKER] = 14,
@@ -568,7 +570,11 @@
         devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
         snd_device = SND_DEVICE_OUT_HEADPHONES;
     } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
-        snd_device = SND_DEVICE_OUT_SPEAKER;
+        if (adev->speaker_lr_swap) {
+            snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE;
+        } else {
+            snd_device = SND_DEVICE_OUT_SPEAKER;
+        }
     } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
         snd_device = SND_DEVICE_OUT_BT_SCO;
     } else if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
@@ -1839,6 +1845,7 @@
     struct str_parms *parms;
     char *str;
     char value[32];
+    int val;
     int ret;
 
     ALOGD("%s: enter: %s", __func__, kvpairs);
@@ -1888,6 +1895,40 @@
             adev->screen_off = true;
     }
 
+    ret = str_parms_get_int(parms, "rotation", &val);
+    if (ret >= 0) {
+        bool reverse_speakers = false;
+        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;
+            break;
+        case 0:
+        case 90:
+        case 180:
+            break;
+        default:
+            ALOGE("%s: unexpected rotation of %d", __func__, val);
+        }
+        pthread_mutex_lock(&adev->lock);
+        if (adev->speaker_lr_swap != reverse_speakers) {
+            adev->speaker_lr_swap = reverse_speakers;
+            // only update the selected device if there is active pcm playback
+            struct audio_usecase *usecase;
+            struct listnode *node;
+            list_for_each(node, &adev->usecase_list) {
+                usecase = node_to_item(node, struct audio_usecase, list);
+                if (usecase->type == PCM_PLAYBACK) {
+                    select_devices(adev, usecase->id);
+                    break;
+                }
+            }
+        }
+        pthread_mutex_unlock(&adev->lock);
+    }
+
     str_parms_destroy(parms);
     ALOGD("%s: exit with code(%d)", __func__, ret);
     return ret;
@@ -2264,6 +2305,7 @@
     adev->bluetooth_nrec = true;
     adev->in_call = false;
     adev->acdb_settings = TTY_MODE_OFF;
+    adev->speaker_lr_swap = false;
     for (i = 0; i < SND_DEVICE_MAX; i++) {
         adev->snd_dev_ref_cnt[i] = 0;
     }
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index cb2f817..08426de 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -51,6 +51,7 @@
     SND_DEVICE_OUT_BEGIN = SND_DEVICE_MIN,
     SND_DEVICE_OUT_HANDSET = SND_DEVICE_OUT_BEGIN,
     SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_REVERSE,
     SND_DEVICE_OUT_HEADPHONES,
     SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
     SND_DEVICE_OUT_VOICE_SPEAKER,
@@ -253,6 +254,7 @@
     struct listnode usecase_list;
     struct audio_route *audio_route;
     int acdb_settings;
+    bool speaker_lr_swap;
 
     bool mic_type_analog;
     bool fluence_in_spkr_mode;