hal: support seamless speaker channels swapping

Change-Id: Ia82254cfb5d2021759f6874e7d7272c75ab91497
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index ddc308d..55f5c19 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -2244,19 +2244,7 @@
             status = -EINVAL;
         }
         if (status == 0) {
-            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;
-                    }
-                }
-            }
+            platform_swap_lr_channels(adev, reverse_speakers);
         }
     }
 
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 7f58388..cb043ed 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -211,7 +211,6 @@
     struct listnode usecase_list;
     struct audio_route *audio_route;
     int acdb_settings;
-    bool speaker_lr_swap;
     struct voice voice;
     unsigned int cur_hdmi_channels;
     bool bt_wb_speech_enabled;
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 4eaf488..454221e 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -81,6 +81,7 @@
     bool fluence_in_voice_call;
     bool fluence_in_voice_rec;
     int  dualmic_config;
+    bool speaker_lr_swap;
 
     void *acdb_handle;
     acdb_init_t acdb_init;
@@ -655,7 +656,7 @@
         devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
         snd_device = SND_DEVICE_OUT_HEADPHONES;
     } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
-        if (adev->speaker_lr_swap)
+        if (my_data->speaker_lr_swap)
             snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE;
         else
             snd_device = SND_DEVICE_OUT_SPEAKER;
@@ -1004,3 +1005,33 @@
 {
     return;
 }
+
+int platform_swap_lr_channels(struct audio_device *adev, bool swap_channels)
+{
+    // only update the selected device if there is active pcm playback
+    struct audio_usecase *usecase;
+    struct listnode *node;
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
+    int status = 0;
+
+    if (my_data->speaker_lr_swap != swap_channels) {
+        my_data->speaker_lr_swap = swap_channels;
+
+        list_for_each(node, &adev->usecase_list) {
+            usecase = node_to_item(node, struct audio_usecase, list);
+            if (usecase->type == PCM_PLAYBACK &&
+                usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
+                const char *mixer_path;
+                if (swap_channels) {
+                    mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_REVERSE);
+                    audio_route_apply_and_update_path(adev->audio_route, mixer_path);
+                } else {
+                    mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER);
+                    audio_route_apply_and_update_path(adev->audio_route, mixer_path);
+                }
+                break;
+            }
+        }
+    }
+    return status;
+}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 7ba0bf0..820b4b7 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -78,6 +78,8 @@
     bool fluence_in_voice_comm;
     bool fluence_in_voice_rec;
     int  dualmic_config;
+    bool speaker_lr_swap;
+
     void *acdb_handle;
     acdb_init_t                acdb_init;
     acdb_deallocate_t          acdb_deallocate;
@@ -1265,7 +1267,7 @@
     } else if (devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
         snd_device = SND_DEVICE_OUT_SPEAKER_SAFE;
     } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
-        if (adev->speaker_lr_swap)
+        if (my_data->speaker_lr_swap)
             snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE;
         else
             snd_device = SND_DEVICE_OUT_SPEAKER;
@@ -1734,3 +1736,32 @@
 done:
     return ret;
 }
+
+int platform_swap_lr_channels(struct audio_device *adev, bool swap_channels)
+{
+    // only update if there is active pcm playback on speaker
+    struct audio_usecase *usecase;
+    struct listnode *node;
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
+
+    if (my_data->speaker_lr_swap != swap_channels) {
+        my_data->speaker_lr_swap = swap_channels;
+
+        list_for_each(node, &adev->usecase_list) {
+            usecase = node_to_item(node, struct audio_usecase, list);
+            if (usecase->type == PCM_PLAYBACK &&
+                usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
+                const char *mixer_path;
+                if (swap_channels) {
+                    mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER_REVERSE);
+                    audio_route_apply_and_update_path(adev->audio_route, mixer_path);
+                } else {
+                    mixer_path = platform_get_snd_device_name(SND_DEVICE_OUT_SPEAKER);
+                    audio_route_apply_and_update_path(adev->audio_route, mixer_path);
+                }
+                break;
+            }
+        }
+    }
+    return 0;
+}
diff --git a/hal/platform_api.h b/hal/platform_api.h
index e50e06d..701399d 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -64,5 +64,5 @@
 int platform_get_usecase_index(const char * usecase);
 int platform_set_usecase_pcm_id(audio_usecase_t usecase, int32_t type, int32_t pcm_id);
 void platform_set_echo_reference(struct audio_device *adev, bool enable, audio_devices_t out_device);
-
+int platform_swap_lr_channels(struct audio_device *adev, bool swap_channels);
 #endif // AUDIO_PLATFORM_API_H