audioflinger: add virtualizer stage mixer thread

Add specialized type of MixerThread for when
a global virtualizer stage with headtracking is used on a
HAL output stream.
This mixer thread has the following requirements:
- Implement a multichannel mixer but a stereo output stream
- Have an output stage effect chain with either a virtualizer stage
effect or plain downmixer effect and possbily other post processing effects
placed after the virtualizer/downmixer
- Being able to handle relatively short audio HAL buffers (5 to 10 ms)
while allowing audio effects to be applied (not a FastMixer).

Bug: 188502620
Test: make

Change-Id: I4dd5b4cd7da7ae0d6562a9a319bdb06b2e31e4e4
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 2b688a1..29ba5f6 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -2569,7 +2569,14 @@
             return thread;
         } else {
             sp<PlaybackThread> thread;
-            if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+            //TODO: b/193496180 use virtualizer stage flag at audio HAL when available
+            if (flags == (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_FAST
+                                                    | AUDIO_OUTPUT_FLAG_DEEP_BUFFER)) {
+                thread = new VirtualizerStageThread(this, outputStream, *output,
+                                                    mSystemReady, mixerConfig);
+                ALOGD("openOutput_l() created virtualizer output: ID %d thread %p",
+                      *output, thread.get());
+            } else if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
                 thread = new OffloadThread(this, outputStream, *output, mSystemReady);
                 ALOGV("openOutput_l() created offload output: ID %d thread %p",
                       *output, thread.get());
@@ -3806,7 +3813,8 @@
                 io = mPlaybackThreads.keyAt(0);
             }
             ALOGV("createEffect() got io %d for effect %s", io, descOut.name);
-        } else if (checkPlaybackThread_l(io) != nullptr) {
+        } else if (checkPlaybackThread_l(io) != nullptr
+                        && sessionId != AUDIO_SESSION_OUTPUT_STAGE) {
             // allow only one effect chain per sessionId on mPlaybackThreads.
             for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
                 const audio_io_handle_t checkIo = mPlaybackThreads.keyAt(i);