AudioMixer: Preserve stereo volume in multi-channel mixing

CrOS exposes 4-channel output for ARC++ and mixes samples in CRAS
server to real channel format, but AudioMixer will discard right
channel volume when mixing a 2-channel track to 4-channel output.
This behavior will cause ARC++ fail on Audio Frequency Line Test
in CTS-V since the right channel can't be tested.

The code is also updated to work for 3, 5, 6, 7, 8 canonical output
channel position masks, as well as continue the mono volume
handling for output channel index masks.

Bug: 110551766
Test: Run CTS-V Audio Frequency Line Test
Test: atest mixerops_benchmark
Change-Id: I4c6ee86d30bb8296f0e32f9a17b1135e1313fd64
diff --git a/media/libaudioprocessing/AudioMixerBase.cpp b/media/libaudioprocessing/AudioMixerBase.cpp
index 75c077d..a169db9 100644
--- a/media/libaudioprocessing/AudioMixerBase.cpp
+++ b/media/libaudioprocessing/AudioMixerBase.cpp
@@ -643,8 +643,16 @@
             if (n & NEEDS_RESAMPLE) {
                 all16BitsStereoNoResample = false;
                 resampling = true;
-                t->hook = TrackBase::getTrackHook(TRACKTYPE_RESAMPLE, t->mMixerChannelCount,
-                        t->mMixerInFormat, t->mMixerFormat);
+                if ((n & NEEDS_CHANNEL_COUNT__MASK) >= NEEDS_CHANNEL_2
+                    && t->useStereoVolume()) {
+                    t->hook = TrackBase::getTrackHook(
+                            TRACKTYPE_RESAMPLESTEREO, t->mMixerChannelCount,
+                            t->mMixerInFormat, t->mMixerFormat);
+                } else {
+                    t->hook = TrackBase::getTrackHook(
+                            TRACKTYPE_RESAMPLE, t->mMixerChannelCount,
+                            t->mMixerInFormat, t->mMixerFormat);
+                }
                 ALOGV_IF((n & NEEDS_CHANNEL_COUNT__MASK) > NEEDS_CHANNEL_2,
                         "Track %d needs downmix + resample", name);
             } else {
@@ -658,8 +666,11 @@
                     all16BitsStereoNoResample = false;
                 }
                 if ((n & NEEDS_CHANNEL_COUNT__MASK) >= NEEDS_CHANNEL_2){
-                    t->hook = TrackBase::getTrackHook(TRACKTYPE_NORESAMPLE, t->mMixerChannelCount,
-                            t->mMixerInFormat, t->mMixerFormat);
+                    t->hook = TrackBase::getTrackHook(
+                            t->useStereoVolume() ? TRACKTYPE_NORESAMPLESTEREO
+                                    : TRACKTYPE_NORESAMPLE,
+                            t->mMixerChannelCount, t->mMixerInFormat,
+                            t->mMixerFormat);
                     ALOGV_IF((n & NEEDS_CHANNEL_COUNT__MASK) > NEEDS_CHANNEL_2,
                             "Track %d needs downmix", name);
                 }
@@ -691,7 +702,8 @@
                         // special case handling due to implicit channel duplication.
                         // Stereo or Multichannel should actually be fine here.
                         mHook = getProcessHook(PROCESSTYPE_NORESAMPLEONETRACK,
-                                t->mMixerChannelCount, t->mMixerInFormat, t->mMixerFormat);
+                                t->mMixerChannelCount, t->mMixerInFormat, t->mMixerFormat,
+                                t->useStereoVolume());
                     }
                 }
             }
@@ -726,7 +738,8 @@
                 const std::shared_ptr<TrackBase> &t = mTracks[mEnabled[0]];
                 // Muted single tracks handled by allMuted above.
                 mHook = getProcessHook(PROCESSTYPE_NORESAMPLEONETRACK,
-                        t->mMixerChannelCount, t->mMixerInFormat, t->mMixerFormat);
+                        t->mMixerChannelCount, t->mMixerInFormat, t->mMixerFormat,
+                        t->useStereoVolume());
             }
         }
     }
@@ -1450,7 +1463,7 @@
         }
 
         const size_t outFrames = b.frameCount;
-        t->volumeMix<MIXTYPE, is_same<TI, float>::value /* USEFLOATVOL */, false /* ADJUSTVOL */> (
+        t->volumeMix<MIXTYPE, std::is_same_v<TI, float> /* USEFLOATVOL */, false /* ADJUSTVOL */> (
                 out, outFrames, in, aux, ramp);
 
         out += outFrames * channels;
@@ -1463,7 +1476,7 @@
         t->bufferProvider->releaseBuffer(&b);
     }
     if (ramp) {
-        t->adjustVolumeRamp(aux != NULL, is_same<TI, float>::value);
+        t->adjustVolumeRamp(aux != NULL, std::is_same_v<TI, float>);
     }
 }
 
@@ -1489,7 +1502,7 @@
         memset(temp, 0, outFrameCount * mMixerChannelCount * sizeof(TO));
         mResampler->resample((int32_t*)temp, outFrameCount, bufferProvider);
 
-        volumeMix<MIXTYPE, is_same<TI, float>::value /* USEFLOATVOL */, true /* ADJUSTVOL */>(
+        volumeMix<MIXTYPE, std::is_same_v<TI, float> /* USEFLOATVOL */, true /* ADJUSTVOL */>(
                 out, outFrameCount, temp, aux, ramp);
 
     } else { // constant volume gain
@@ -1513,7 +1526,7 @@
     ALOGVV("track__NoResample\n");
     const TI *in = static_cast<const TI *>(mIn);
 
-    volumeMix<MIXTYPE, is_same<TI, float>::value /* USEFLOATVOL */, true /* ADJUSTVOL */>(
+    volumeMix<MIXTYPE, std::is_same_v<TI, float> /* USEFLOATVOL */, true /* ADJUSTVOL */>(
             out, frameCount, in, aux, needsRamp());
 
     // MIXTYPE_MONOEXPAND reads a single input channel and expands to NCHAN output channels.
@@ -1601,6 +1614,21 @@
             break;
         }
         break;
+    case TRACKTYPE_RESAMPLESTEREO:
+        switch (mixerInFormat) {
+        case AUDIO_FORMAT_PCM_FLOAT:
+            return (AudioMixerBase::hook_t) &TrackBase::track__Resample<
+                    MIXTYPE_MULTI_STEREOVOL, float /*TO*/, float /*TI*/,
+                    TYPE_AUX>;
+        case AUDIO_FORMAT_PCM_16_BIT:
+            return (AudioMixerBase::hook_t) &TrackBase::track__Resample<
+                    MIXTYPE_MULTI_STEREOVOL, int32_t /*TO*/, int16_t /*TI*/,
+                    TYPE_AUX>;
+        default:
+            LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat);
+            break;
+        }
+        break;
     case TRACKTYPE_NORESAMPLEMONO:
         switch (mixerInFormat) {
         case AUDIO_FORMAT_PCM_FLOAT:
@@ -1627,6 +1655,21 @@
             break;
         }
         break;
+    case TRACKTYPE_NORESAMPLESTEREO:
+        switch (mixerInFormat) {
+        case AUDIO_FORMAT_PCM_FLOAT:
+            return (AudioMixerBase::hook_t) &TrackBase::track__NoResample<
+                    MIXTYPE_MULTI_STEREOVOL, float /*TO*/, float /*TI*/,
+                    TYPE_AUX>;
+        case AUDIO_FORMAT_PCM_16_BIT:
+            return (AudioMixerBase::hook_t) &TrackBase::track__NoResample<
+                    MIXTYPE_MULTI_STEREOVOL, int32_t /*TO*/, int16_t /*TI*/,
+                    TYPE_AUX>;
+        default:
+            LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat);
+            break;
+        }
+        break;
     default:
         LOG_ALWAYS_FATAL("bad trackType: %d", trackType);
         break;
@@ -1644,7 +1687,8 @@
 /* static */
 AudioMixerBase::process_hook_t AudioMixerBase::getProcessHook(
         int processType, uint32_t channelCount,
-        audio_format_t mixerInFormat, audio_format_t mixerOutFormat)
+        audio_format_t mixerInFormat, audio_format_t mixerOutFormat,
+        bool stereoVolume)
 {
     if (processType != PROCESSTYPE_NORESAMPLEONETRACK) { // Only NORESAMPLEONETRACK
         LOG_ALWAYS_FATAL("bad processType: %d", processType);
@@ -1654,36 +1698,79 @@
         return &AudioMixerBase::process__oneTrack16BitsStereoNoResampling;
     }
     LOG_ALWAYS_FATAL_IF(channelCount > MAX_NUM_CHANNELS);
-    switch (mixerInFormat) {
-    case AUDIO_FORMAT_PCM_FLOAT:
-        switch (mixerOutFormat) {
+
+    if (stereoVolume) { // templated arguments require explicit values.
+        switch (mixerInFormat) {
         case AUDIO_FORMAT_PCM_FLOAT:
-            return &AudioMixerBase::process__noResampleOneTrack<
-                    MIXTYPE_MULTI_SAVEONLY, float /*TO*/, float /*TI*/, TYPE_AUX>;
+            switch (mixerOutFormat) {
+            case AUDIO_FORMAT_PCM_FLOAT:
+                return &AudioMixerBase::process__noResampleOneTrack<
+                        MIXTYPE_MULTI_SAVEONLY_STEREOVOL, float /*TO*/,
+                        float /*TI*/, TYPE_AUX>;
+            case AUDIO_FORMAT_PCM_16_BIT:
+                return &AudioMixerBase::process__noResampleOneTrack<
+                        MIXTYPE_MULTI_SAVEONLY_STEREOVOL, int16_t /*TO*/,
+                        float /*TI*/, TYPE_AUX>;
+            default:
+                LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat);
+                break;
+            }
+            break;
         case AUDIO_FORMAT_PCM_16_BIT:
-            return &AudioMixerBase::process__noResampleOneTrack<
-                    MIXTYPE_MULTI_SAVEONLY, int16_t /*TO*/, float /*TI*/, TYPE_AUX>;
+            switch (mixerOutFormat) {
+            case AUDIO_FORMAT_PCM_FLOAT:
+                return &AudioMixerBase::process__noResampleOneTrack<
+                        MIXTYPE_MULTI_SAVEONLY_STEREOVOL, float /*TO*/,
+                        int16_t /*TI*/, TYPE_AUX>;
+            case AUDIO_FORMAT_PCM_16_BIT:
+                return &AudioMixerBase::process__noResampleOneTrack<
+                        MIXTYPE_MULTI_SAVEONLY_STEREOVOL, int16_t /*TO*/,
+                        int16_t /*TI*/, TYPE_AUX>;
+            default:
+                LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat);
+                break;
+            }
+            break;
         default:
-            LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat);
+            LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat);
             break;
         }
-        break;
-    case AUDIO_FORMAT_PCM_16_BIT:
-        switch (mixerOutFormat) {
-        case AUDIO_FORMAT_PCM_FLOAT:
-            return &AudioMixerBase::process__noResampleOneTrack<
-                    MIXTYPE_MULTI_SAVEONLY, float /*TO*/, int16_t /*TI*/, TYPE_AUX>;
-        case AUDIO_FORMAT_PCM_16_BIT:
-            return &AudioMixerBase::process__noResampleOneTrack<
-                    MIXTYPE_MULTI_SAVEONLY, int16_t /*TO*/, int16_t /*TI*/, TYPE_AUX>;
-        default:
-            LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat);
-            break;
-        }
-        break;
-    default:
-        LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat);
-        break;
+    } else {
+          switch (mixerInFormat) {
+          case AUDIO_FORMAT_PCM_FLOAT:
+              switch (mixerOutFormat) {
+              case AUDIO_FORMAT_PCM_FLOAT:
+                  return &AudioMixerBase::process__noResampleOneTrack<
+                          MIXTYPE_MULTI_SAVEONLY, float /*TO*/,
+                          float /*TI*/, TYPE_AUX>;
+              case AUDIO_FORMAT_PCM_16_BIT:
+                  return &AudioMixerBase::process__noResampleOneTrack<
+                          MIXTYPE_MULTI_SAVEONLY, int16_t /*TO*/,
+                          float /*TI*/, TYPE_AUX>;
+              default:
+                  LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat);
+                  break;
+              }
+              break;
+          case AUDIO_FORMAT_PCM_16_BIT:
+              switch (mixerOutFormat) {
+              case AUDIO_FORMAT_PCM_FLOAT:
+                  return &AudioMixerBase::process__noResampleOneTrack<
+                          MIXTYPE_MULTI_SAVEONLY, float /*TO*/,
+                          int16_t /*TI*/, TYPE_AUX>;
+              case AUDIO_FORMAT_PCM_16_BIT:
+                  return &AudioMixerBase::process__noResampleOneTrack<
+                          MIXTYPE_MULTI_SAVEONLY, int16_t /*TO*/,
+                          int16_t /*TI*/, TYPE_AUX>;
+              default:
+                  LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat);
+                  break;
+              }
+              break;
+          default:
+              LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat);
+              break;
+          }
     }
     return NULL;
 }