Loading media/libaudioprocessing/AudioMixerBase.cpp +122 −35 Original line number Diff line number Diff line Loading @@ -643,8 +643,16 @@ void AudioMixerBase::process__validate() if (n & NEEDS_RESAMPLE) { all16BitsStereoNoResample = false; resampling = true; t->hook = TrackBase::getTrackHook(TRACKTYPE_RESAMPLE, t->mMixerChannelCount, 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 { Loading @@ -658,8 +666,11 @@ void AudioMixerBase::process__validate() 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); } Loading Loading @@ -691,7 +702,8 @@ void AudioMixerBase::process__validate() // 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()); } } } Loading Loading @@ -726,7 +738,8 @@ void AudioMixerBase::process__validate() 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()); } } } Loading Loading @@ -1450,7 +1463,7 @@ void AudioMixerBase::process__noResampleOneTrack() } 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; Loading @@ -1463,7 +1476,7 @@ void AudioMixerBase::process__noResampleOneTrack() 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>); } } Loading @@ -1489,7 +1502,7 @@ void AudioMixerBase::TrackBase::track__Resample(TO* out, size_t outFrameCount, T 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 Loading @@ -1513,7 +1526,7 @@ void AudioMixerBase::TrackBase::track__NoResample( 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. Loading Loading @@ -1601,6 +1614,21 @@ AudioMixerBase::hook_t AudioMixerBase::TrackBase::getTrackHook(int trackType, ui 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: Loading @@ -1627,6 +1655,21 @@ AudioMixerBase::hook_t AudioMixerBase::TrackBase::getTrackHook(int trackType, ui 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; Loading @@ -1644,7 +1687,8 @@ AudioMixerBase::hook_t AudioMixerBase::TrackBase::getTrackHook(int trackType, ui /* 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); Loading @@ -1654,15 +1698,19 @@ AudioMixerBase::process_hook_t AudioMixerBase::getProcessHook( return &AudioMixerBase::process__oneTrack16BitsStereoNoResampling; } LOG_ALWAYS_FATAL_IF(channelCount > MAX_NUM_CHANNELS); if (stereoVolume) { // templated arguments require explicit values. 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>; MIXTYPE_MULTI_SAVEONLY_STEREOVOL, 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>; MIXTYPE_MULTI_SAVEONLY_STEREOVOL, int16_t /*TO*/, float /*TI*/, TYPE_AUX>; default: LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat); break; Loading @@ -1672,10 +1720,12 @@ AudioMixerBase::process_hook_t AudioMixerBase::getProcessHook( switch (mixerOutFormat) { case AUDIO_FORMAT_PCM_FLOAT: return &AudioMixerBase::process__noResampleOneTrack< MIXTYPE_MULTI_SAVEONLY, float /*TO*/, int16_t /*TI*/, TYPE_AUX>; MIXTYPE_MULTI_SAVEONLY_STEREOVOL, 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>; MIXTYPE_MULTI_SAVEONLY_STEREOVOL, int16_t /*TO*/, int16_t /*TI*/, TYPE_AUX>; default: LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat); break; Loading @@ -1685,6 +1735,43 @@ AudioMixerBase::process_hook_t AudioMixerBase::getProcessHook( 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; } Loading media/libaudioprocessing/AudioMixerOps.h +125 −72 Original line number Diff line number Diff line Loading @@ -19,21 +19,10 @@ namespace android { /* Behavior of is_same<>::value is true if the types are identical, * false otherwise. Identical to the STL std::is_same. */ template<typename T, typename U> struct is_same { static const bool value = false; }; template<typename T> struct is_same<T, T> // partial specialization { static const bool value = true; }; // Hack to make static_assert work in a constexpr // https://en.cppreference.com/w/cpp/language/if template <int N> inline constexpr bool dependent_false = false; /* MixMul is a multiplication operator to scale an audio input signal * by a volume gain, with the formula: Loading Loading @@ -179,7 +168,7 @@ inline int16_t MixMul<int16_t, float, float>(float value, float volume) { template <typename TO, typename TI> inline void MixAccum(TO *auxaccum, TI value) { if (!is_same<TO, TI>::value) { if (!std::is_same_v<TO, TI>) { LOG_ALWAYS_FATAL("MixAccum type not properly specialized: %zu %zu\n", sizeof(TO), sizeof(TI)); } Loading Loading @@ -228,7 +217,67 @@ enum { MIXTYPE_MULTI_SAVEONLY, MIXTYPE_MULTI_MONOVOL, MIXTYPE_MULTI_SAVEONLY_MONOVOL, MIXTYPE_MULTI_STEREOVOL, MIXTYPE_MULTI_SAVEONLY_STEREOVOL, }; /* * TODO: We should work on non-interleaved streams - the * complexity of working on interleaved streams is now getting * too high, and likely limits compiler optimization. */ template <int MIXTYPE, int NCHAN, typename TO, typename TI, typename TV, typename F> void stereoVolumeHelper(TO*& out, const TI*& in, const TV *vol, F f) { static_assert(NCHAN > 0 && NCHAN <= 8); static_assert(MIXTYPE == MIXTYPE_MULTI_STEREOVOL || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL); auto proc = [](auto& a, const auto& b) { if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL) { a += b; } else { a = b; } }; // HALs should only expose the canonical channel masks. proc(*out++, f(*in++, vol[0])); // front left if constexpr (NCHAN == 1) return; proc(*out++, f(*in++, vol[1])); // front right if constexpr (NCHAN == 2) return; if constexpr (NCHAN == 4) { proc(*out++, f(*in++, vol[0])); // back left proc(*out++, f(*in++, vol[1])); // back right return; } // TODO: Precompute center volume if not ramping. std::decay_t<TV> center; if constexpr (std::is_floating_point_v<TV>) { center = (vol[0] + vol[1]) * 0.5; // do not use divide } else { center = (vol[0] >> 1) + (vol[1] >> 1); // rounds to 0. } proc(*out++, f(*in++, center)); // center (or 2.1 LFE) if constexpr (NCHAN == 3) return; if constexpr (NCHAN == 5) { proc(*out++, f(*in++, vol[0])); // back left proc(*out++, f(*in++, vol[1])); // back right return; } proc(*out++, f(*in++, center)); // lfe proc(*out++, f(*in++, vol[0])); // back left proc(*out++, f(*in++, vol[1])); // back right if constexpr (NCHAN == 6) return; if constexpr (NCHAN == 7) { proc(*out++, f(*in++, center)); // back center return; } // NCHAN == 8 proc(*out++, f(*in++, vol[0])); // side left proc(*out++, f(*in++, vol[1])); // side right } /* * The volumeRampMulti and volumeRamp functions take a MIXTYPE Loading Loading @@ -271,6 +320,12 @@ enum { * MIXTYPE_MULTI_SAVEONLY_MONOVOL: * Same as MIXTYPE_MULTI_SAVEONLY, but uses only volume[0]. * * MIXTYPE_MULTI_STEREOVOL: * Same as MIXTYPE_MULTI, but uses only volume[0] and volume[1]. * * MIXTYPE_MULTI_SAVEONLY_STEREOVOL: * Same as MIXTYPE_MULTI_SAVEONLY, but uses only volume[0] and volume[1]. * */ template <int MIXTYPE, int NCHAN, Loading @@ -284,41 +339,42 @@ inline void volumeRampMulti(TO* out, size_t frameCount, if (aux != NULL) { do { TA auxaccum = 0; switch (MIXTYPE) { case MIXTYPE_MULTI: if constexpr (MIXTYPE == MIXTYPE_MULTI) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum); vol[i] += volinc[i]; } break; case MIXTYPE_MONOEXPAND: } else if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum); vol[i] += volinc[i]; } in++; break; case MIXTYPE_MULTI_SAVEONLY: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) { for (int i = 0; i < NCHAN; ++i) { *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum); vol[i] += volinc[i]; } break; case MIXTYPE_MULTI_MONOVOL: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_MONOVOL) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum); } vol[0] += volinc[0]; break; case MIXTYPE_MULTI_SAVEONLY_MONOVOL: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY_MONOVOL) { for (int i = 0; i < NCHAN; ++i) { *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum); } vol[0] += volinc[0]; break; default: LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE); break; } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL) { stereoVolumeHelper<MIXTYPE, NCHAN>( out, in, vol, [&auxaccum] (auto &a, const auto &b) { return MixMulAux<TO, TI, TV, TA>(a, b, &auxaccum); }); vol[0] += volinc[0]; vol[1] += volinc[1]; } else /* constexpr */ { static_assert(dependent_false<MIXTYPE>, "invalid mixtype"); } auxaccum /= NCHAN; *aux++ += MixMul<TA, TA, TAV>(auxaccum, *vola); Loading @@ -326,41 +382,41 @@ inline void volumeRampMulti(TO* out, size_t frameCount, } while (--frameCount); } else { do { switch (MIXTYPE) { case MIXTYPE_MULTI: if constexpr (MIXTYPE == MIXTYPE_MULTI) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMul<TO, TI, TV>(*in++, vol[i]); vol[i] += volinc[i]; } break; case MIXTYPE_MONOEXPAND: } else if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMul<TO, TI, TV>(*in, vol[i]); vol[i] += volinc[i]; } in++; break; case MIXTYPE_MULTI_SAVEONLY: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) { for (int i = 0; i < NCHAN; ++i) { *out++ = MixMul<TO, TI, TV>(*in++, vol[i]); vol[i] += volinc[i]; } break; case MIXTYPE_MULTI_MONOVOL: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_MONOVOL) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMul<TO, TI, TV>(*in++, vol[0]); } vol[0] += volinc[0]; break; case MIXTYPE_MULTI_SAVEONLY_MONOVOL: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY_MONOVOL) { for (int i = 0; i < NCHAN; ++i) { *out++ = MixMul<TO, TI, TV>(*in++, vol[0]); } vol[0] += volinc[0]; break; default: LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE); break; } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL) { stereoVolumeHelper<MIXTYPE, NCHAN>(out, in, vol, [] (auto &a, const auto &b) { return MixMul<TO, TI, TV>(a, b); }); vol[0] += volinc[0]; vol[1] += volinc[1]; } else /* constexpr */ { static_assert(dependent_false<MIXTYPE>, "invalid mixtype"); } } while (--frameCount); } Loading @@ -377,72 +433,69 @@ inline void volumeMulti(TO* out, size_t frameCount, if (aux != NULL) { do { TA auxaccum = 0; switch (MIXTYPE) { case MIXTYPE_MULTI: if constexpr (MIXTYPE == MIXTYPE_MULTI) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum); } break; case MIXTYPE_MONOEXPAND: } else if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum); } in++; break; case MIXTYPE_MULTI_SAVEONLY: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) { for (int i = 0; i < NCHAN; ++i) { *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum); } break; case MIXTYPE_MULTI_MONOVOL: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_MONOVOL) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum); } break; case MIXTYPE_MULTI_SAVEONLY_MONOVOL: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY_MONOVOL) { for (int i = 0; i < NCHAN; ++i) { *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum); } break; default: LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE); break; } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL) { stereoVolumeHelper<MIXTYPE, NCHAN>( out, in, vol, [&auxaccum] (auto &a, const auto &b) { return MixMulAux<TO, TI, TV, TA>(a, b, &auxaccum); }); } else /* constexpr */ { static_assert(dependent_false<MIXTYPE>, "invalid mixtype"); } auxaccum /= NCHAN; *aux++ += MixMul<TA, TA, TAV>(auxaccum, vola); } while (--frameCount); } else { do { switch (MIXTYPE) { case MIXTYPE_MULTI: if constexpr (MIXTYPE == MIXTYPE_MULTI) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMul<TO, TI, TV>(*in++, vol[i]); } break; case MIXTYPE_MONOEXPAND: } else if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMul<TO, TI, TV>(*in, vol[i]); } in++; break; case MIXTYPE_MULTI_SAVEONLY: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) { for (int i = 0; i < NCHAN; ++i) { *out++ = MixMul<TO, TI, TV>(*in++, vol[i]); } break; case MIXTYPE_MULTI_MONOVOL: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_MONOVOL) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMul<TO, TI, TV>(*in++, vol[0]); } break; case MIXTYPE_MULTI_SAVEONLY_MONOVOL: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY_MONOVOL) { for (int i = 0; i < NCHAN; ++i) { *out++ = MixMul<TO, TI, TV>(*in++, vol[0]); } break; default: LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE); break; } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL) { stereoVolumeHelper<MIXTYPE, NCHAN>(out, in, vol, [] (auto &a, const auto &b) { return MixMul<TO, TI, TV>(a, b); }); } else /* constexpr */ { static_assert(dependent_false<MIXTYPE>, "invalid mixtype"); } } while (--frameCount); } Loading media/libaudioprocessing/include/media/AudioMixerBase.h +12 −1 Original line number Diff line number Diff line Loading @@ -188,13 +188,20 @@ public: enum { TRACKTYPE_NOP, TRACKTYPE_RESAMPLE, TRACKTYPE_RESAMPLESTEREO, TRACKTYPE_NORESAMPLE, TRACKTYPE_NORESAMPLEMONO, TRACKTYPE_NORESAMPLESTEREO, }; // process hook functionality using process_hook_t = void(AudioMixerBase::*)(); static bool isAudioChannelPositionMask(audio_channel_mask_t channelMask) { return audio_channel_mask_get_representation(channelMask) == AUDIO_CHANNEL_REPRESENTATION_POSITION; } struct TrackBase; using hook_t = void(TrackBase::*)( int32_t* output, size_t numOutFrames, int32_t* temp, int32_t* aux); Loading @@ -219,6 +226,9 @@ public: size_t getUnreleasedFrames() const { return mResampler.get() != nullptr ? mResampler->getUnreleasedFrames() : 0; }; bool useStereoVolume() const { return channelMask == AUDIO_CHANNEL_OUT_STEREO && isAudioChannelPositionMask(mMixerChannelMask); } static hook_t getTrackHook(int trackType, uint32_t channelCount, audio_format_t mixerInFormat, audio_format_t mixerOutFormat); Loading Loading @@ -327,7 +337,8 @@ public: void process__noResampleOneTrack(); static process_hook_t getProcessHook(int processType, uint32_t channelCount, audio_format_t mixerInFormat, audio_format_t mixerOutFormat); audio_format_t mixerInFormat, audio_format_t mixerOutFormat, bool useStereoVolume); static void convertMixerFormat(void *out, audio_format_t mixerOutFormat, void *in, audio_format_t mixerInFormat, size_t sampleCount); Loading media/libaudioprocessing/tests/Android.bp +23 −0 Original line number Diff line number Diff line Loading @@ -55,3 +55,26 @@ cc_binary { srcs: ["test-resampler.cpp"], static_libs: ["libsndfile"], } // // build mixerops objdump // // This is used to verify proper optimization of the code. // // For example, use: // ./prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android-objdump // -d --source ./out/target/product/crosshatch/symbols/system/bin/mixerops_objdump // cc_binary { name: "mixerops_objdump", srcs: ["mixerops_objdump.cpp"], } // // build mixerops benchmark // cc_benchmark { name: "mixerops_benchmark", srcs: ["mixerops_benchmark.cpp"], static_libs: ["libgoogle-benchmark"], } media/libaudioprocessing/tests/mixerops_benchmark.cpp 0 → 100644 +102 −0 File added.Preview size limit exceeded, changes collapsed. Show changes Loading
media/libaudioprocessing/AudioMixerBase.cpp +122 −35 Original line number Diff line number Diff line Loading @@ -643,8 +643,16 @@ void AudioMixerBase::process__validate() if (n & NEEDS_RESAMPLE) { all16BitsStereoNoResample = false; resampling = true; t->hook = TrackBase::getTrackHook(TRACKTYPE_RESAMPLE, t->mMixerChannelCount, 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 { Loading @@ -658,8 +666,11 @@ void AudioMixerBase::process__validate() 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); } Loading Loading @@ -691,7 +702,8 @@ void AudioMixerBase::process__validate() // 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()); } } } Loading Loading @@ -726,7 +738,8 @@ void AudioMixerBase::process__validate() 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()); } } } Loading Loading @@ -1450,7 +1463,7 @@ void AudioMixerBase::process__noResampleOneTrack() } 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; Loading @@ -1463,7 +1476,7 @@ void AudioMixerBase::process__noResampleOneTrack() 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>); } } Loading @@ -1489,7 +1502,7 @@ void AudioMixerBase::TrackBase::track__Resample(TO* out, size_t outFrameCount, T 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 Loading @@ -1513,7 +1526,7 @@ void AudioMixerBase::TrackBase::track__NoResample( 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. Loading Loading @@ -1601,6 +1614,21 @@ AudioMixerBase::hook_t AudioMixerBase::TrackBase::getTrackHook(int trackType, ui 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: Loading @@ -1627,6 +1655,21 @@ AudioMixerBase::hook_t AudioMixerBase::TrackBase::getTrackHook(int trackType, ui 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; Loading @@ -1644,7 +1687,8 @@ AudioMixerBase::hook_t AudioMixerBase::TrackBase::getTrackHook(int trackType, ui /* 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); Loading @@ -1654,15 +1698,19 @@ AudioMixerBase::process_hook_t AudioMixerBase::getProcessHook( return &AudioMixerBase::process__oneTrack16BitsStereoNoResampling; } LOG_ALWAYS_FATAL_IF(channelCount > MAX_NUM_CHANNELS); if (stereoVolume) { // templated arguments require explicit values. 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>; MIXTYPE_MULTI_SAVEONLY_STEREOVOL, 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>; MIXTYPE_MULTI_SAVEONLY_STEREOVOL, int16_t /*TO*/, float /*TI*/, TYPE_AUX>; default: LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat); break; Loading @@ -1672,10 +1720,12 @@ AudioMixerBase::process_hook_t AudioMixerBase::getProcessHook( switch (mixerOutFormat) { case AUDIO_FORMAT_PCM_FLOAT: return &AudioMixerBase::process__noResampleOneTrack< MIXTYPE_MULTI_SAVEONLY, float /*TO*/, int16_t /*TI*/, TYPE_AUX>; MIXTYPE_MULTI_SAVEONLY_STEREOVOL, 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>; MIXTYPE_MULTI_SAVEONLY_STEREOVOL, int16_t /*TO*/, int16_t /*TI*/, TYPE_AUX>; default: LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat); break; Loading @@ -1685,6 +1735,43 @@ AudioMixerBase::process_hook_t AudioMixerBase::getProcessHook( 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; } Loading
media/libaudioprocessing/AudioMixerOps.h +125 −72 Original line number Diff line number Diff line Loading @@ -19,21 +19,10 @@ namespace android { /* Behavior of is_same<>::value is true if the types are identical, * false otherwise. Identical to the STL std::is_same. */ template<typename T, typename U> struct is_same { static const bool value = false; }; template<typename T> struct is_same<T, T> // partial specialization { static const bool value = true; }; // Hack to make static_assert work in a constexpr // https://en.cppreference.com/w/cpp/language/if template <int N> inline constexpr bool dependent_false = false; /* MixMul is a multiplication operator to scale an audio input signal * by a volume gain, with the formula: Loading Loading @@ -179,7 +168,7 @@ inline int16_t MixMul<int16_t, float, float>(float value, float volume) { template <typename TO, typename TI> inline void MixAccum(TO *auxaccum, TI value) { if (!is_same<TO, TI>::value) { if (!std::is_same_v<TO, TI>) { LOG_ALWAYS_FATAL("MixAccum type not properly specialized: %zu %zu\n", sizeof(TO), sizeof(TI)); } Loading Loading @@ -228,7 +217,67 @@ enum { MIXTYPE_MULTI_SAVEONLY, MIXTYPE_MULTI_MONOVOL, MIXTYPE_MULTI_SAVEONLY_MONOVOL, MIXTYPE_MULTI_STEREOVOL, MIXTYPE_MULTI_SAVEONLY_STEREOVOL, }; /* * TODO: We should work on non-interleaved streams - the * complexity of working on interleaved streams is now getting * too high, and likely limits compiler optimization. */ template <int MIXTYPE, int NCHAN, typename TO, typename TI, typename TV, typename F> void stereoVolumeHelper(TO*& out, const TI*& in, const TV *vol, F f) { static_assert(NCHAN > 0 && NCHAN <= 8); static_assert(MIXTYPE == MIXTYPE_MULTI_STEREOVOL || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL); auto proc = [](auto& a, const auto& b) { if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL) { a += b; } else { a = b; } }; // HALs should only expose the canonical channel masks. proc(*out++, f(*in++, vol[0])); // front left if constexpr (NCHAN == 1) return; proc(*out++, f(*in++, vol[1])); // front right if constexpr (NCHAN == 2) return; if constexpr (NCHAN == 4) { proc(*out++, f(*in++, vol[0])); // back left proc(*out++, f(*in++, vol[1])); // back right return; } // TODO: Precompute center volume if not ramping. std::decay_t<TV> center; if constexpr (std::is_floating_point_v<TV>) { center = (vol[0] + vol[1]) * 0.5; // do not use divide } else { center = (vol[0] >> 1) + (vol[1] >> 1); // rounds to 0. } proc(*out++, f(*in++, center)); // center (or 2.1 LFE) if constexpr (NCHAN == 3) return; if constexpr (NCHAN == 5) { proc(*out++, f(*in++, vol[0])); // back left proc(*out++, f(*in++, vol[1])); // back right return; } proc(*out++, f(*in++, center)); // lfe proc(*out++, f(*in++, vol[0])); // back left proc(*out++, f(*in++, vol[1])); // back right if constexpr (NCHAN == 6) return; if constexpr (NCHAN == 7) { proc(*out++, f(*in++, center)); // back center return; } // NCHAN == 8 proc(*out++, f(*in++, vol[0])); // side left proc(*out++, f(*in++, vol[1])); // side right } /* * The volumeRampMulti and volumeRamp functions take a MIXTYPE Loading Loading @@ -271,6 +320,12 @@ enum { * MIXTYPE_MULTI_SAVEONLY_MONOVOL: * Same as MIXTYPE_MULTI_SAVEONLY, but uses only volume[0]. * * MIXTYPE_MULTI_STEREOVOL: * Same as MIXTYPE_MULTI, but uses only volume[0] and volume[1]. * * MIXTYPE_MULTI_SAVEONLY_STEREOVOL: * Same as MIXTYPE_MULTI_SAVEONLY, but uses only volume[0] and volume[1]. * */ template <int MIXTYPE, int NCHAN, Loading @@ -284,41 +339,42 @@ inline void volumeRampMulti(TO* out, size_t frameCount, if (aux != NULL) { do { TA auxaccum = 0; switch (MIXTYPE) { case MIXTYPE_MULTI: if constexpr (MIXTYPE == MIXTYPE_MULTI) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum); vol[i] += volinc[i]; } break; case MIXTYPE_MONOEXPAND: } else if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum); vol[i] += volinc[i]; } in++; break; case MIXTYPE_MULTI_SAVEONLY: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) { for (int i = 0; i < NCHAN; ++i) { *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum); vol[i] += volinc[i]; } break; case MIXTYPE_MULTI_MONOVOL: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_MONOVOL) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum); } vol[0] += volinc[0]; break; case MIXTYPE_MULTI_SAVEONLY_MONOVOL: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY_MONOVOL) { for (int i = 0; i < NCHAN; ++i) { *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum); } vol[0] += volinc[0]; break; default: LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE); break; } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL) { stereoVolumeHelper<MIXTYPE, NCHAN>( out, in, vol, [&auxaccum] (auto &a, const auto &b) { return MixMulAux<TO, TI, TV, TA>(a, b, &auxaccum); }); vol[0] += volinc[0]; vol[1] += volinc[1]; } else /* constexpr */ { static_assert(dependent_false<MIXTYPE>, "invalid mixtype"); } auxaccum /= NCHAN; *aux++ += MixMul<TA, TA, TAV>(auxaccum, *vola); Loading @@ -326,41 +382,41 @@ inline void volumeRampMulti(TO* out, size_t frameCount, } while (--frameCount); } else { do { switch (MIXTYPE) { case MIXTYPE_MULTI: if constexpr (MIXTYPE == MIXTYPE_MULTI) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMul<TO, TI, TV>(*in++, vol[i]); vol[i] += volinc[i]; } break; case MIXTYPE_MONOEXPAND: } else if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMul<TO, TI, TV>(*in, vol[i]); vol[i] += volinc[i]; } in++; break; case MIXTYPE_MULTI_SAVEONLY: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) { for (int i = 0; i < NCHAN; ++i) { *out++ = MixMul<TO, TI, TV>(*in++, vol[i]); vol[i] += volinc[i]; } break; case MIXTYPE_MULTI_MONOVOL: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_MONOVOL) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMul<TO, TI, TV>(*in++, vol[0]); } vol[0] += volinc[0]; break; case MIXTYPE_MULTI_SAVEONLY_MONOVOL: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY_MONOVOL) { for (int i = 0; i < NCHAN; ++i) { *out++ = MixMul<TO, TI, TV>(*in++, vol[0]); } vol[0] += volinc[0]; break; default: LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE); break; } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL) { stereoVolumeHelper<MIXTYPE, NCHAN>(out, in, vol, [] (auto &a, const auto &b) { return MixMul<TO, TI, TV>(a, b); }); vol[0] += volinc[0]; vol[1] += volinc[1]; } else /* constexpr */ { static_assert(dependent_false<MIXTYPE>, "invalid mixtype"); } } while (--frameCount); } Loading @@ -377,72 +433,69 @@ inline void volumeMulti(TO* out, size_t frameCount, if (aux != NULL) { do { TA auxaccum = 0; switch (MIXTYPE) { case MIXTYPE_MULTI: if constexpr (MIXTYPE == MIXTYPE_MULTI) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum); } break; case MIXTYPE_MONOEXPAND: } else if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMulAux<TO, TI, TV, TA>(*in, vol[i], &auxaccum); } in++; break; case MIXTYPE_MULTI_SAVEONLY: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) { for (int i = 0; i < NCHAN; ++i) { *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[i], &auxaccum); } break; case MIXTYPE_MULTI_MONOVOL: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_MONOVOL) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum); } break; case MIXTYPE_MULTI_SAVEONLY_MONOVOL: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY_MONOVOL) { for (int i = 0; i < NCHAN; ++i) { *out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum); } break; default: LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE); break; } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL) { stereoVolumeHelper<MIXTYPE, NCHAN>( out, in, vol, [&auxaccum] (auto &a, const auto &b) { return MixMulAux<TO, TI, TV, TA>(a, b, &auxaccum); }); } else /* constexpr */ { static_assert(dependent_false<MIXTYPE>, "invalid mixtype"); } auxaccum /= NCHAN; *aux++ += MixMul<TA, TA, TAV>(auxaccum, vola); } while (--frameCount); } else { do { switch (MIXTYPE) { case MIXTYPE_MULTI: if constexpr (MIXTYPE == MIXTYPE_MULTI) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMul<TO, TI, TV>(*in++, vol[i]); } break; case MIXTYPE_MONOEXPAND: } else if constexpr (MIXTYPE == MIXTYPE_MONOEXPAND) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMul<TO, TI, TV>(*in, vol[i]); } in++; break; case MIXTYPE_MULTI_SAVEONLY: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY) { for (int i = 0; i < NCHAN; ++i) { *out++ = MixMul<TO, TI, TV>(*in++, vol[i]); } break; case MIXTYPE_MULTI_MONOVOL: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_MONOVOL) { for (int i = 0; i < NCHAN; ++i) { *out++ += MixMul<TO, TI, TV>(*in++, vol[0]); } break; case MIXTYPE_MULTI_SAVEONLY_MONOVOL: } else if constexpr (MIXTYPE == MIXTYPE_MULTI_SAVEONLY_MONOVOL) { for (int i = 0; i < NCHAN; ++i) { *out++ = MixMul<TO, TI, TV>(*in++, vol[0]); } break; default: LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE); break; } else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL) { stereoVolumeHelper<MIXTYPE, NCHAN>(out, in, vol, [] (auto &a, const auto &b) { return MixMul<TO, TI, TV>(a, b); }); } else /* constexpr */ { static_assert(dependent_false<MIXTYPE>, "invalid mixtype"); } } while (--frameCount); } Loading
media/libaudioprocessing/include/media/AudioMixerBase.h +12 −1 Original line number Diff line number Diff line Loading @@ -188,13 +188,20 @@ public: enum { TRACKTYPE_NOP, TRACKTYPE_RESAMPLE, TRACKTYPE_RESAMPLESTEREO, TRACKTYPE_NORESAMPLE, TRACKTYPE_NORESAMPLEMONO, TRACKTYPE_NORESAMPLESTEREO, }; // process hook functionality using process_hook_t = void(AudioMixerBase::*)(); static bool isAudioChannelPositionMask(audio_channel_mask_t channelMask) { return audio_channel_mask_get_representation(channelMask) == AUDIO_CHANNEL_REPRESENTATION_POSITION; } struct TrackBase; using hook_t = void(TrackBase::*)( int32_t* output, size_t numOutFrames, int32_t* temp, int32_t* aux); Loading @@ -219,6 +226,9 @@ public: size_t getUnreleasedFrames() const { return mResampler.get() != nullptr ? mResampler->getUnreleasedFrames() : 0; }; bool useStereoVolume() const { return channelMask == AUDIO_CHANNEL_OUT_STEREO && isAudioChannelPositionMask(mMixerChannelMask); } static hook_t getTrackHook(int trackType, uint32_t channelCount, audio_format_t mixerInFormat, audio_format_t mixerOutFormat); Loading Loading @@ -327,7 +337,8 @@ public: void process__noResampleOneTrack(); static process_hook_t getProcessHook(int processType, uint32_t channelCount, audio_format_t mixerInFormat, audio_format_t mixerOutFormat); audio_format_t mixerInFormat, audio_format_t mixerOutFormat, bool useStereoVolume); static void convertMixerFormat(void *out, audio_format_t mixerOutFormat, void *in, audio_format_t mixerInFormat, size_t sampleCount); Loading
media/libaudioprocessing/tests/Android.bp +23 −0 Original line number Diff line number Diff line Loading @@ -55,3 +55,26 @@ cc_binary { srcs: ["test-resampler.cpp"], static_libs: ["libsndfile"], } // // build mixerops objdump // // This is used to verify proper optimization of the code. // // For example, use: // ./prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android-objdump // -d --source ./out/target/product/crosshatch/symbols/system/bin/mixerops_objdump // cc_binary { name: "mixerops_objdump", srcs: ["mixerops_objdump.cpp"], } // // build mixerops benchmark // cc_benchmark { name: "mixerops_benchmark", srcs: ["mixerops_benchmark.cpp"], static_libs: ["libgoogle-benchmark"], }
media/libaudioprocessing/tests/mixerops_benchmark.cpp 0 → 100644 +102 −0 File added.Preview size limit exceeded, changes collapsed. Show changes