Audio: Fixes for FCC_LIMIT validation
Test: SoundPool(Aac|Haptic|Midi|Ogg)Test
Test: AudioEffectTest, AudioPreProcessingTest
Test: BassBoostTest, EnvReverbTest, EqualizerTest, LoudnessEnhancerTest
Test: PresetReverbTest, VirtualizerTest, VisualizerTest
Bug: 189325443
Change-Id: I0ce958a2e111d8f55391a00fafbc95135bee288e
diff --git a/media/libaudioprocessing/AudioMixerBase.cpp b/media/libaudioprocessing/AudioMixerBase.cpp
index a54e22f..f30eb54 100644
--- a/media/libaudioprocessing/AudioMixerBase.cpp
+++ b/media/libaudioprocessing/AudioMixerBase.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "AudioMixer"
//#define LOG_NDEBUG 0
+#include <array>
#include <sstream>
#include <string.h>
@@ -1295,8 +1296,29 @@
// Needs to derive a compile time constant (constexpr). Could be targeted to go
// to a MONOVOL mixtype based on MAX_NUM_VOLUMES, but that's an unnecessary complication.
-#define MIXTYPE_MONOVOL(mixtype) ((mixtype) == MIXTYPE_MULTI ? MIXTYPE_MULTI_MONOVOL : \
- (mixtype) == MIXTYPE_MULTI_SAVEONLY ? MIXTYPE_MULTI_SAVEONLY_MONOVOL : (mixtype))
+
+constexpr int MIXTYPE_MONOVOL(int mixtype, int channels) {
+ if (channels <= FCC_2) {
+ return mixtype;
+ } else if (mixtype == MIXTYPE_MULTI) {
+ return MIXTYPE_MULTI_MONOVOL;
+ } else if (mixtype == MIXTYPE_MULTI_SAVEONLY) {
+ return MIXTYPE_MULTI_SAVEONLY_MONOVOL;
+ } else {
+ return mixtype;
+ }
+}
+
+// Helper to make a functional array from volumeRampMulti.
+template <int MIXTYPE, typename TO, typename TI, typename TV, typename TA, typename TAV,
+ std::size_t ... Is>
+static constexpr auto makeVRMArray(std::index_sequence<Is...>)
+{
+ using F = void(*)(TO*, size_t, const TI*, TA*, TV*, const TV*, TAV*, TAV);
+ return std::array<F, sizeof...(Is)>{
+ { &volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE, Is + 1), Is + 1, TO, TI, TV, TA, TAV> ...}
+ };
+}
/* MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration)
* TO: int32_t (Q4.27) or float
@@ -1308,40 +1330,26 @@
static void volumeRampMulti(uint32_t channels, TO* out, size_t frameCount,
const TI* in, TA* aux, TV *vol, const TV *volinc, TAV *vola, TAV volainc)
{
- switch (channels) {
- case 1:
- volumeRampMulti<MIXTYPE, 1>(out, frameCount, in, aux, vol, volinc, vola, volainc);
- break;
- case 2:
- volumeRampMulti<MIXTYPE, 2>(out, frameCount, in, aux, vol, volinc, vola, volainc);
- break;
- case 3:
- volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 3>(out,
- frameCount, in, aux, vol, volinc, vola, volainc);
- break;
- case 4:
- volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 4>(out,
- frameCount, in, aux, vol, volinc, vola, volainc);
- break;
- case 5:
- volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 5>(out,
- frameCount, in, aux, vol, volinc, vola, volainc);
- break;
- case 6:
- volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 6>(out,
- frameCount, in, aux, vol, volinc, vola, volainc);
- break;
- case 7:
- volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 7>(out,
- frameCount, in, aux, vol, volinc, vola, volainc);
- break;
- case 8:
- volumeRampMulti<MIXTYPE_MONOVOL(MIXTYPE), 8>(out,
- frameCount, in, aux, vol, volinc, vola, volainc);
- break;
+ static constexpr auto volumeRampMultiArray =
+ makeVRMArray<MIXTYPE, TO, TI, TV, TA, TAV>(std::make_index_sequence<FCC_LIMIT>());
+ if (channels > 0 && channels <= volumeRampMultiArray.size()) {
+ volumeRampMultiArray[channels - 1](out, frameCount, in, aux, vol, volinc, vola, volainc);
+ } else {
+ ALOGE("%s: invalid channel count:%d", __func__, channels);
}
}
+// Helper to make a functional array from volumeMulti.
+template <int MIXTYPE, typename TO, typename TI, typename TV, typename TA, typename TAV,
+ std::size_t ... Is>
+static constexpr auto makeVMArray(std::index_sequence<Is...>)
+{
+ using F = void(*)(TO*, size_t, const TI*, TA*, const TV*, TAV);
+ return std::array<F, sizeof...(Is)>{
+ { &volumeMulti<MIXTYPE_MONOVOL(MIXTYPE, Is + 1), Is + 1, TO, TI, TV, TA, TAV> ... }
+ };
+}
+
/* MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration)
* TO: int32_t (Q4.27) or float
* TI: int32_t (Q4.27) or int16_t (Q0.15) or float
@@ -1352,31 +1360,12 @@
static void volumeMulti(uint32_t channels, TO* out, size_t frameCount,
const TI* in, TA* aux, const TV *vol, TAV vola)
{
- switch (channels) {
- case 1:
- volumeMulti<MIXTYPE, 1>(out, frameCount, in, aux, vol, vola);
- break;
- case 2:
- volumeMulti<MIXTYPE, 2>(out, frameCount, in, aux, vol, vola);
- break;
- case 3:
- volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 3>(out, frameCount, in, aux, vol, vola);
- break;
- case 4:
- volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 4>(out, frameCount, in, aux, vol, vola);
- break;
- case 5:
- volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 5>(out, frameCount, in, aux, vol, vola);
- break;
- case 6:
- volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 6>(out, frameCount, in, aux, vol, vola);
- break;
- case 7:
- volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 7>(out, frameCount, in, aux, vol, vola);
- break;
- case 8:
- volumeMulti<MIXTYPE_MONOVOL(MIXTYPE), 8>(out, frameCount, in, aux, vol, vola);
- break;
+ static constexpr auto volumeMultiArray =
+ makeVMArray<MIXTYPE, TO, TI, TV, TA, TAV>(std::make_index_sequence<FCC_LIMIT>());
+ if (channels > 0 && channels <= volumeMultiArray.size()) {
+ volumeMultiArray[channels - 1](out, frameCount, in, aux, vol, vola);
+ } else {
+ ALOGE("%s: invalid channel count:%d", __func__, channels);
}
}
diff --git a/media/libaudioprocessing/AudioMixerOps.h b/media/libaudioprocessing/AudioMixerOps.h
index a56d9cb..cd47dc6 100644
--- a/media/libaudioprocessing/AudioMixerOps.h
+++ b/media/libaudioprocessing/AudioMixerOps.h
@@ -293,6 +293,16 @@
// NCHAN == 8
proc(*out++, f(inp(), vol[0])); // side left
proc(*out++, f(inp(), vol[1])); // side right
+ if constexpr (NCHAN > FCC_8) {
+ // Mutes to zero extended surround channels.
+ // 7.1.4 has the correct behavior.
+ // 22.2 has the behavior that FLC and FRC will be mixed instead
+ // of SL and SR and LFE will be center, not left.
+ for (int i = 8; i < NCHAN; ++i) {
+ // TODO: Consider using android::audio_utils::channels::kSideFromChannelIdx
+ proc(*out++, f(inp(), 0.f));
+ }
+ }
}
/*
diff --git a/media/libaudioprocessing/AudioResamplerDyn.cpp b/media/libaudioprocessing/AudioResamplerDyn.cpp
index 21d3d36..2292b19 100644
--- a/media/libaudioprocessing/AudioResamplerDyn.cpp
+++ b/media/libaudioprocessing/AudioResamplerDyn.cpp
@@ -548,61 +548,73 @@
LOG_ALWAYS_FATAL_IF(mChannelCount < 1 || mChannelCount > FCC_LIMIT,
"Resampler channels(%d) must be between 1 to %d", mChannelCount, FCC_LIMIT);
// stride 16 (falls back to stride 2 for machines that do not support NEON)
+
+
+// For now use a #define as a compiler generated function table requires renaming.
+#pragma push_macro("AUDIORESAMPLERDYN_CASE")
+#undef AUDIORESAMPLERDYN_CASE
+#define AUDIORESAMPLERDYN_CASE(CHANNEL, LOCKED) \
+ case CHANNEL: if constexpr (CHANNEL <= FCC_LIMIT) {\
+ mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<CHANNEL, LOCKED, 16>; \
+ } break
+
if (locked) {
switch (mChannelCount) {
- case 1:
- mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<1, true, 16>;
- break;
- case 2:
- mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<2, true, 16>;
- break;
- case 3:
- mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<3, true, 16>;
- break;
- case 4:
- mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<4, true, 16>;
- break;
- case 5:
- mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<5, true, 16>;
- break;
- case 6:
- mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<6, true, 16>;
- break;
- case 7:
- mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<7, true, 16>;
- break;
- case 8:
- mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<8, true, 16>;
- break;
+ AUDIORESAMPLERDYN_CASE(1, true);
+ AUDIORESAMPLERDYN_CASE(2, true);
+ AUDIORESAMPLERDYN_CASE(3, true);
+ AUDIORESAMPLERDYN_CASE(4, true);
+ AUDIORESAMPLERDYN_CASE(5, true);
+ AUDIORESAMPLERDYN_CASE(6, true);
+ AUDIORESAMPLERDYN_CASE(7, true);
+ AUDIORESAMPLERDYN_CASE(8, true);
+ AUDIORESAMPLERDYN_CASE(9, true);
+ AUDIORESAMPLERDYN_CASE(10, true);
+ AUDIORESAMPLERDYN_CASE(11, true);
+ AUDIORESAMPLERDYN_CASE(12, true);
+ AUDIORESAMPLERDYN_CASE(13, true);
+ AUDIORESAMPLERDYN_CASE(14, true);
+ AUDIORESAMPLERDYN_CASE(15, true);
+ AUDIORESAMPLERDYN_CASE(16, true);
+ AUDIORESAMPLERDYN_CASE(17, true);
+ AUDIORESAMPLERDYN_CASE(18, true);
+ AUDIORESAMPLERDYN_CASE(19, true);
+ AUDIORESAMPLERDYN_CASE(20, true);
+ AUDIORESAMPLERDYN_CASE(21, true);
+ AUDIORESAMPLERDYN_CASE(22, true);
+ AUDIORESAMPLERDYN_CASE(23, true);
+ AUDIORESAMPLERDYN_CASE(24, true);
}
} else {
switch (mChannelCount) {
- case 1:
- mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<1, false, 16>;
- break;
- case 2:
- mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<2, false, 16>;
- break;
- case 3:
- mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<3, false, 16>;
- break;
- case 4:
- mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<4, false, 16>;
- break;
- case 5:
- mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<5, false, 16>;
- break;
- case 6:
- mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<6, false, 16>;
- break;
- case 7:
- mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<7, false, 16>;
- break;
- case 8:
- mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<8, false, 16>;
- break;
+ AUDIORESAMPLERDYN_CASE(1, false);
+ AUDIORESAMPLERDYN_CASE(2, false);
+ AUDIORESAMPLERDYN_CASE(3, false);
+ AUDIORESAMPLERDYN_CASE(4, false);
+ AUDIORESAMPLERDYN_CASE(5, false);
+ AUDIORESAMPLERDYN_CASE(6, false);
+ AUDIORESAMPLERDYN_CASE(7, false);
+ AUDIORESAMPLERDYN_CASE(8, false);
+ AUDIORESAMPLERDYN_CASE(9, false);
+ AUDIORESAMPLERDYN_CASE(10, false);
+ AUDIORESAMPLERDYN_CASE(11, false);
+ AUDIORESAMPLERDYN_CASE(12, false);
+ AUDIORESAMPLERDYN_CASE(13, false);
+ AUDIORESAMPLERDYN_CASE(14, false);
+ AUDIORESAMPLERDYN_CASE(15, false);
+ AUDIORESAMPLERDYN_CASE(16, false);
+ AUDIORESAMPLERDYN_CASE(17, false);
+ AUDIORESAMPLERDYN_CASE(18, false);
+ AUDIORESAMPLERDYN_CASE(19, false);
+ AUDIORESAMPLERDYN_CASE(20, false);
+ AUDIORESAMPLERDYN_CASE(21, false);
+ AUDIORESAMPLERDYN_CASE(22, false);
+ AUDIORESAMPLERDYN_CASE(23, false);
+ AUDIORESAMPLERDYN_CASE(24, false);
}
}
+#pragma pop_macro("AUDIORESAMPLERDYN_CASE")
+
#ifdef DEBUG_RESAMPLER
printf("channels:%d %s stride:%d %s coef:%d shift:%d\n",
mChannelCount, locked ? "locked" : "interpolated",
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 13e2ced..88d4eaf 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -48,6 +48,15 @@
/*static*/ const FastMixerState FastMixer::sInitial;
+static audio_channel_mask_t getChannelMaskFromCount(size_t count) {
+ const audio_channel_mask_t mask = audio_channel_out_mask_from_count(count);
+ if (mask == AUDIO_CHANNEL_INVALID) {
+ // some counts have no positional masks. TODO: Update this to return index count?
+ return audio_channel_mask_for_index_assignment_from_count(count);
+ }
+ return mask;
+}
+
FastMixer::FastMixer(audio_io_handle_t parentIoHandle)
: FastThread("cycle_ms", "load_us"),
// mFastTrackNames
@@ -79,7 +88,7 @@
mDummyDumpState = &mDummyFastMixerDumpState;
// TODO: Add channel mask to NBAIO_Format.
// We assume that the channel mask must be a valid positional channel mask.
- mSinkChannelMask = audio_channel_out_mask_from_count(mSinkChannelCount);
+ mSinkChannelMask = getChannelMaskFromCount(mSinkChannelCount);
unsigned i;
for (i = 0; i < FastMixerState::sMaxFastTracks; ++i) {
@@ -238,7 +247,7 @@
LOG_ALWAYS_FATAL_IF(mSinkChannelCount > AudioMixer::MAX_NUM_CHANNELS);
if (mSinkChannelMask == AUDIO_CHANNEL_NONE) {
- mSinkChannelMask = audio_channel_out_mask_from_count(mSinkChannelCount);
+ mSinkChannelMask = getChannelMaskFromCount(mSinkChannelCount);
}
mAudioChannelCount = mSinkChannelCount - audio_channel_count_from_out_mask(
mSinkChannelMask & AUDIO_CHANNEL_HAPTIC_ALL);