add offloaded audio visualizer

Add library for visualizer effect used when
audio decompression is offloaded to QCOM audio DSP.
The implementation reads PCM back from the proxy port
in the audio DSP.
The audio HAL dynamically loads the effect library if present
and indicates offloaded output activity.
The PCM capture is only active when an offloaded output
is active and at least one effect is enabled on this output.

Bug: 8174410.

Change-Id: Ic78de932f9116e246494f9171c1cc7c3e35a0ea1
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 4f92ea3..c2997c6 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -29,6 +29,7 @@
 #include <sys/time.h>
 #include <stdlib.h>
 #include <math.h>
+#include <dlfcn.h>
 #include <sys/resource.h>
 #include <sys/prctl.h>
 
@@ -797,6 +798,10 @@
         return -EINVAL;
     }
 
+    if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD &&
+            adev->visualizer_stop_output != NULL)
+        adev->visualizer_stop_output(out->handle);
+
     /* 1. Get and set stream specific mixer controls */
     disable_audio_route(adev, uc_info, true);
 
@@ -863,6 +868,9 @@
         }
         if (out->offload_callback)
             compress_nonblock(out->compr, out->non_blocking);
+
+        if (adev->visualizer_start_output != NULL)
+            adev->visualizer_start_output(out->handle);
     }
     ALOGV("%s: exit", __func__);
     return 0;
@@ -1742,6 +1750,7 @@
     out->sample_rate = config->sample_rate;
     out->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
     out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO;
+    out->handle = handle;
 
     /* Init use case and pcm_config */
     if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT &&
@@ -2263,6 +2272,22 @@
         *device = NULL;
         return -EINVAL;
     }
+
+    if (access(VISUALIZER_LIBRARY_PATH, R_OK) == 0) {
+        adev->visualizer_lib = dlopen(VISUALIZER_LIBRARY_PATH, RTLD_NOW);
+        if (adev->visualizer_lib == NULL) {
+            ALOGE("%s: DLOPEN failed for %s", __func__, VISUALIZER_LIBRARY_PATH);
+        } else {
+            ALOGV("%s: DLOPEN successful for %s", __func__, VISUALIZER_LIBRARY_PATH);
+            adev->visualizer_start_output =
+                        (int (*)(audio_io_handle_t))dlsym(adev->visualizer_lib,
+                                                        "visualizer_hal_start_output");
+            adev->visualizer_stop_output =
+                        (int (*)(audio_io_handle_t))dlsym(adev->visualizer_lib,
+                                                        "visualizer_hal_stop_output");
+        }
+    }
+
     *device = &adev->device.common;
 
     ALOGV("%s: exit", __func__);