Loading services/audioflinger/Android.mk +3 −0 Original line number Diff line number Diff line Loading @@ -115,6 +115,9 @@ LOCAL_SRC_FILES:= \ AudioResamplerSinc.cpp.arm \ AudioResamplerDyn.cpp.arm LOCAL_C_INCLUDES := \ $(call include-path-for, audio-utils) LOCAL_SHARED_LIBRARIES := \ libcutils \ libdl \ Loading services/audioflinger/AudioMixer.cpp +172 −70 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <stdint.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <sys/types.h> #include <utils/Errors.h> Loading Loading @@ -293,17 +294,32 @@ int AudioMixer::getTrackName(audio_channel_mask_t channelMask, // assume default parameters for the track, except where noted below track_t* t = &mState.tracks[n]; t->needs = 0; // Integer volume. // Currently integer volume is kept for the legacy integer mixer. // Will be removed when the legacy mixer path is removed. t->volume[0] = UNITY_GAIN_INT; t->volume[1] = UNITY_GAIN_INT; // no initialization needed // t->prevVolume[0] // t->prevVolume[1] t->prevVolume[0] = UNITY_GAIN_INT << 16; t->prevVolume[1] = UNITY_GAIN_INT << 16; t->volumeInc[0] = 0; t->volumeInc[1] = 0; t->auxLevel = 0; t->auxInc = 0; t->prevAuxLevel = 0; // Floating point volume. t->mVolume[0] = UNITY_GAIN_FLOAT; t->mVolume[1] = UNITY_GAIN_FLOAT; t->mPrevVolume[0] = UNITY_GAIN_FLOAT; t->mPrevVolume[1] = UNITY_GAIN_FLOAT; t->mVolumeInc[0] = 0.; t->mVolumeInc[1] = 0.; t->mAuxLevel = 0.; t->mAuxInc = 0.; t->mPrevAuxLevel = 0.; // no initialization needed // t->prevAuxLevel // t->frameCount t->channelCount = audio_channel_count_from_out_mask(channelMask); t->enabled = false; Loading Loading @@ -574,39 +590,68 @@ void AudioMixer::disable(int name) /* Sets the volume ramp variables for the AudioMixer. * * The volume ramp variables are used to transition between the previous * volume to the target volume. The duration of the transition is * set by ramp, which is either 0 for immediate, or typically one state * framecount period. * The volume ramp variables are used to transition from the previous * volume to the set volume. ramp controls the duration of the transition. * Its value is typically one state framecount period, but may also be 0, * meaning "immediate." * * FIXME: 1) Volume ramp is enabled only if there is a nonzero integer increment * even if there is a nonzero floating point increment (in that case, the volume * change is immediate). This restriction should be changed when the legacy mixer * is removed (see #2). * FIXME: 2) Integer volume variables are used for Legacy mixing and should be removed * when no longer needed. * * @param newFloatValue new volume target in float [0.0, 1.0]. * @param ramp number of frames to increment over. ramp is 0 if the volume * should be set immediately. * @param volume reference to the U4.12 target volume, set on return. * @param prevVolume reference to the U4.27 previous volume, set on return. * @param volumeInc reference to the increment per output audio frame, set on return. * @param newVolume set volume target in floating point [0.0, 1.0]. * @param ramp number of frames to increment over. if ramp is 0, the volume * should be set immediately. Currently ramp should not exceed 65535 (frames). * @param pIntSetVolume pointer to the U4.12 integer target volume, set on return. * @param pIntPrevVolume pointer to the U4.28 integer previous volume, set on return. * @param pIntVolumeInc pointer to the U4.28 increment per output audio frame, set on return. * @param pSetVolume pointer to the float target volume, set on return. * @param pPrevVolume pointer to the float previous volume, set on return. * @param pVolumeInc pointer to the float increment per output audio frame, set on return. * @return true if the volume has changed, false if volume is same. */ static inline bool setVolumeRampVariables(float newFloatValue, int32_t ramp, int16_t &volume, int32_t &prevVolume, int32_t &volumeInc) { int32_t newValue = newFloatValue * AudioMixer::UNITY_GAIN_INT; if (newValue > AudioMixer::UNITY_GAIN_INT) { newValue = AudioMixer::UNITY_GAIN_INT; } else if (newValue < 0) { ALOGE("negative volume %.7g", newFloatValue); newValue = 0; // should never happen, but for safety check. } if (newValue == volume) { static inline bool setVolumeRampVariables(float newVolume, int32_t ramp, int16_t *pIntSetVolume, int32_t *pIntPrevVolume, int32_t *pIntVolumeInc, float *pSetVolume, float *pPrevVolume, float *pVolumeInc) { if (newVolume == *pSetVolume) { return false; } /* set the floating point volume variables */ if (ramp != 0) { *pVolumeInc = (newVolume - *pSetVolume) / ramp; *pPrevVolume = *pSetVolume; } else { *pVolumeInc = 0; *pPrevVolume = newVolume; } *pSetVolume = newVolume; /* set the legacy integer volume variables */ int32_t intVolume = newVolume * AudioMixer::UNITY_GAIN_INT; if (intVolume > AudioMixer::UNITY_GAIN_INT) { intVolume = AudioMixer::UNITY_GAIN_INT; } else if (intVolume < 0) { ALOGE("negative volume %.7g", newVolume); intVolume = 0; // should never happen, but for safety check. } if (intVolume == *pIntSetVolume) { *pIntVolumeInc = 0; /* TODO: integer/float workaround: ignore floating volume ramp */ *pVolumeInc = 0; *pPrevVolume = newVolume; return true; } if (ramp != 0) { volumeInc = ((newValue - volume) << 16) / ramp; prevVolume = (volumeInc == 0 ? newValue : volume) << 16; *pIntVolumeInc = ((intVolume - *pIntSetVolume) << 16) / ramp; *pIntPrevVolume = (*pIntVolumeInc == 0 ? intVolume : *pIntSetVolume) << 16; } else { volumeInc = 0; prevVolume = newValue << 16; *pIntVolumeInc = 0; *pIntPrevVolume = intVolume << 16; } volume = newValue; *pIntSetVolume = intVolume; return true; } Loading Loading @@ -716,8 +761,10 @@ void AudioMixer::setParameter(int name, int target, int param, void *value) case VOLUME1: if (setVolumeRampVariables(*reinterpret_cast<float*>(value), target == RAMP_VOLUME ? mState.frameCount : 0, track.volume[param - VOLUME0], track.prevVolume[param - VOLUME0], track.volumeInc[param - VOLUME0])) { &track.volume[param - VOLUME0], &track.prevVolume[param - VOLUME0], &track.volumeInc[param - VOLUME0], &track.mVolume[param - VOLUME0], &track.mPrevVolume[param - VOLUME0], &track.mVolumeInc[param - VOLUME0])) { ALOGV("setParameter(%s, VOLUME%d: %04x)", target == VOLUME ? "VOLUME" : "RAMP_VOLUME", param - VOLUME0, track.volume[param - VOLUME0]); Loading @@ -725,10 +772,10 @@ void AudioMixer::setParameter(int name, int target, int param, void *value) } break; case AUXLEVEL: //ALOG_ASSERT(0 <= valueInt && valueInt <= MAX_GAIN_INT, "bad aux level %d", valueInt); if (setVolumeRampVariables(*reinterpret_cast<float*>(value), target == RAMP_VOLUME ? mState.frameCount : 0, track.auxLevel, track.prevAuxLevel, track.auxInc)) { &track.auxLevel, &track.prevAuxLevel, &track.auxInc, &track.mAuxLevel, &track.mPrevAuxLevel, &track.mAuxInc)) { ALOGV("setParameter(%s, AUXLEVEL: %04x)", target == VOLUME ? "VOLUME" : "RAMP_VOLUME", track.auxLevel); invalidateState(1 << name); Loading Loading @@ -777,21 +824,58 @@ bool AudioMixer::track_t::setResampler(uint32_t value, uint32_t devSampleRate) return false; } inline void AudioMixer::track_t::adjustVolumeRamp(bool aux) /* Checks to see if the volume ramp has completed and clears the increment * variables appropriately. * * FIXME: There is code to handle int/float ramp variable switchover should it not * complete within a mixer buffer processing call, but it is preferred to avoid switchover * due to precision issues. The switchover code is included for legacy code purposes * and can be removed once the integer volume is removed. * * It is not sufficient to clear only the volumeInc integer variable because * if one channel requires ramping, all channels are ramped. * * There is a bit of duplicated code here, but it keeps backward compatibility. */ inline void AudioMixer::track_t::adjustVolumeRamp(bool aux, bool useFloat) { if (useFloat) { for (uint32_t i=0 ; i<MAX_NUM_CHANNELS ; i++) { if (mVolumeInc[i] != 0 && fabs(mVolume[i] - mPrevVolume[i]) <= fabs(mVolumeInc[i])) { volumeInc[i] = 0; prevVolume[i] = volume[i] << 16; mVolumeInc[i] = 0.; mPrevVolume[i] = mVolume[i]; } else { //ALOGV("ramp: %f %f %f", mVolume[i], mPrevVolume[i], mVolumeInc[i]); prevVolume[i] = u4_28_from_float(mPrevVolume[i]); } } } else { for (uint32_t i=0 ; i<MAX_NUM_CHANNELS ; i++) { if (((volumeInc[i]>0) && (((prevVolume[i]+volumeInc[i])>>16) >= volume[i])) || ((volumeInc[i]<0) && (((prevVolume[i]+volumeInc[i])>>16) <= volume[i]))) { volumeInc[i] = 0; prevVolume[i] = volume[i] << 16; mVolumeInc[i] = 0.; mPrevVolume[i] = mVolume[i]; } else { //ALOGV("ramp: %d %d %d", volume[i] << 16, prevVolume[i], volumeInc[i]); mPrevVolume[i] = float_from_u4_28(prevVolume[i]); } } } /* TODO: aux is always integer regardless of output buffer type */ if (aux) { if (((auxInc>0) && (((prevAuxLevel+auxInc)>>16) >= auxLevel)) || ((auxInc<0) && (((prevAuxLevel+auxInc)>>16) <= auxLevel))) { auxInc = 0; prevAuxLevel = auxLevel << 16; mAuxInc = 0.; mPrevAuxLevel = mAuxLevel; } else { //ALOGV("aux ramp: %d %d %d", auxLevel << 16, prevAuxLevel, auxInc); } } } Loading Loading @@ -985,7 +1069,7 @@ void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFram // always resample with unity gain when sending to auxiliary buffer to be able // to apply send level after resampling // TODO: modify each resampler to support aux channel? t->resampler->setVolume(UNITY_GAIN_INT, UNITY_GAIN_INT); t->resampler->setVolume(UNITY_GAIN_FLOAT, UNITY_GAIN_FLOAT); memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t)); t->resampler->resample(temp, outFrameCount, t->bufferProvider); if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc)) { Loading @@ -995,7 +1079,7 @@ void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFram } } else { if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1])) { t->resampler->setVolume(UNITY_GAIN_INT, UNITY_GAIN_INT); t->resampler->setVolume(UNITY_GAIN_FLOAT, UNITY_GAIN_FLOAT); memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t)); t->resampler->resample(temp, outFrameCount, t->bufferProvider); volumeRampStereo(t, out, outFrameCount, temp, aux); Loading @@ -1003,7 +1087,7 @@ void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFram // constant gain else { t->resampler->setVolume(t->volume[0], t->volume[1]); t->resampler->setVolume(t->mVolume[0], t->mVolume[1]); t->resampler->resample(out, outFrameCount, t->bufferProvider); } } Loading Loading @@ -1721,6 +1805,36 @@ int64_t AudioMixer::calculateOutputPTS(const track_t& t, int64_t basePTS, ALOGW_IF(!sIsMultichannelCapable, "unable to find downmix effect"); } template <int MIXTYPE, int NCHAN, bool USEFLOATVOL, bool ADJUSTVOL, typename TO, typename TI, typename TA> void AudioMixer::volumeMix(TO *out, size_t outFrames, const TI *in, TA *aux, bool ramp, AudioMixer::track_t *t) { if (USEFLOATVOL) { if (ramp) { volumeRampMulti<MIXTYPE, NCHAN>(out, outFrames, in, aux, t->mPrevVolume, t->mVolumeInc, &t->prevAuxLevel, t->auxInc); if (ADJUSTVOL) { t->adjustVolumeRamp(aux != NULL, true); } } else { volumeMulti<MIXTYPE, NCHAN>(out, outFrames, in, aux, t->mVolume, t->auxLevel); } } else { if (ramp) { volumeRampMulti<MIXTYPE, NCHAN>(out, outFrames, in, aux, t->prevVolume, t->volumeInc, &t->prevAuxLevel, t->auxInc); if (ADJUSTVOL) { t->adjustVolumeRamp(aux != NULL); } } else { volumeMulti<MIXTYPE, NCHAN>(out, outFrames, in, aux, t->volume, t->auxLevel); } } } /* This process hook is called when there is a single track without * aux buffer, volume ramp, or resampling. * TODO: Update the hook selection: this can properly handle aux and ramp. Loading Loading @@ -1757,13 +1871,9 @@ void AudioMixer::process_NoResampleOneTrack(state_t* state, int64_t pts) } const size_t outFrames = b.frameCount; if (ramp) { volumeRampMulti<MIXTYPE_MULTI_SAVEONLY, NCHAN>(out, outFrames, in, aux, t->prevVolume, t->volumeInc, &t->prevAuxLevel, t->auxInc); } else { volumeMulti<MIXTYPE_MULTI_SAVEONLY, NCHAN>(out, outFrames, in, aux, t->volume, t->auxLevel); } volumeMix<MIXTYPE, NCHAN, is_same<TI, float>::value, false> (out, outFrames, in, aux, ramp, t); out += outFrames * NCHAN; if (aux != NULL) { aux += NCHAN; Loading @@ -1774,7 +1884,7 @@ void AudioMixer::process_NoResampleOneTrack(state_t* state, int64_t pts) t->bufferProvider->releaseBuffer(&b); } if (ramp) { t->adjustVolumeRamp(aux != NULL); t->adjustVolumeRamp(aux != NULL, is_same<TI, float>::value); } } Loading @@ -1792,19 +1902,15 @@ void AudioMixer::track__Resample(track_t* t, TO* out, size_t outFrameCount, TO* // if ramp: resample with unity gain to temp buffer and scale/mix in 2nd step. // if aux != NULL: resample with unity gain to temp buffer then apply send level. t->resampler->setVolume(UNITY_GAIN_INT, UNITY_GAIN_INT); t->resampler->setVolume(UNITY_GAIN_FLOAT, UNITY_GAIN_FLOAT); memset(temp, 0, outFrameCount * NCHAN * sizeof(TO)); t->resampler->resample((int32_t*)temp, outFrameCount, t->bufferProvider); if (ramp) { volumeRampMulti<MIXTYPE_MULTI, NCHAN>(out, outFrameCount, temp, aux, t->prevVolume, t->volumeInc, &t->prevAuxLevel, t->auxInc); t->adjustVolumeRamp(aux != NULL); } else { volumeMulti<MIXTYPE_MULTI, NCHAN>(out, outFrameCount, temp, aux, t->volume, t->auxLevel); } volumeMix<MIXTYPE, NCHAN, is_same<TI, float>::value, true>(out, outFrameCount, temp, aux, ramp, t); } else { // constant volume gain t->resampler->setVolume(t->volume[0], t->volume[1]); t->resampler->setVolume(t->mVolume[0], t->mVolume[1]); t->resampler->resample((int32_t*)out, outFrameCount, t->bufferProvider); } } Loading @@ -1819,13 +1925,9 @@ void AudioMixer::track__NoResample(track_t* t, TO* out, size_t frameCount, ALOGVV("track__NoResample\n"); const TI *in = static_cast<const TI *>(t->in); if (t->needsRamp()) { volumeRampMulti<MIXTYPE, NCHAN>(out, frameCount, in, aux, t->prevVolume, t->volumeInc, &t->prevAuxLevel, t->auxInc); t->adjustVolumeRamp(aux != NULL); } else { volumeMulti<MIXTYPE, NCHAN>(out, frameCount, in, aux, t->volume, t->auxLevel); } volumeMix<MIXTYPE, NCHAN, is_same<TI, float>::value, true>(out, frameCount, in, aux, t->needsRamp(), t); // MIXTYPE_MONOEXPAND reads a single input channel and expands to NCHAN output channels. // MIXTYPE_MULTI reads NCHAN input channels and places to NCHAN output channels. in += (MIXTYPE == MIXTYPE_MONOEXPAND) ? frameCount : frameCount * NCHAN; Loading services/audioflinger/AudioMixer.h +26 −3 Original line number Diff line number Diff line Loading @@ -163,8 +163,9 @@ private: struct track_t { uint32_t needs; // TODO: Eventually remove legacy integer volume settings union { int16_t volume[MAX_NUM_CHANNELS]; // [0]3.12 fixed point int16_t volume[MAX_NUM_CHANNELS]; // U4.12 fixed point (top bit should be zero) int32_t volumeRL; }; Loading Loading @@ -217,7 +218,13 @@ private: audio_format_t mMixerInFormat; // mix internal format AUDIO_FORMAT_PCM_(FLOAT|16_BIT) // each track must be converted to this format. int32_t mUnused[1]; // alignment padding float mVolume[MAX_NUM_CHANNELS]; // floating point set volume float mPrevVolume[MAX_NUM_CHANNELS]; // floating point previous volume float mVolumeInc[MAX_NUM_CHANNELS]; // floating point volume increment float mAuxLevel; // floating point set aux level float mPrevAuxLevel; // floating point prev aux level float mAuxInc; // floating point aux increment // 16-byte boundary Loading @@ -225,7 +232,7 @@ private: bool setResampler(uint32_t sampleRate, uint32_t devSampleRate); bool doesResample() const { return resampler != NULL; } void resetResampler() { if (resampler != NULL) resampler->reset(); } void adjustVolumeRamp(bool aux); void adjustVolumeRamp(bool aux, bool useFloat = false); size_t getUnreleasedFrames() const { return resampler != NULL ? resampler->getUnreleasedFrames() : 0; }; }; Loading Loading @@ -349,6 +356,22 @@ private: static pthread_once_t sOnceControl; static void sInitRoutine(); /* multi-format volume mixing function (calls template functions * in AudioMixerOps.h). The template parameters are as follows: * * MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration) * NCHAN (number of channels, 2 for now) * USEFLOATVOL (set to true if float volume is used) * ADJUSTVOL (set to true if volume ramp parameters needs adjustment afterwards) * TO: int32_t (Q4.27) or float * TI: int32_t (Q4.27) or int16_t (Q0.15) or float * TA: int32_t (Q4.27) */ template <int MIXTYPE, int NCHAN, bool USEFLOATVOL, bool ADJUSTVOL, typename TO, typename TI, typename TA> static void volumeMix(TO *out, size_t outFrames, const TI *in, TA *aux, bool ramp, AudioMixer::track_t *t); // multi-format process hooks template <int MIXTYPE, int NCHAN, typename TO, typename TI, typename TA> static void process_NoResampleOneTrack(state_t* state, int64_t pts); Loading services/audioflinger/AudioMixerOps.h +40 −0 Original line number Diff line number Diff line Loading @@ -136,6 +136,46 @@ inline int16_t MixMul<int16_t, int32_t, int32_t>(int32_t value, int32_t volume) return clamp16(MixMul<int32_t, int32_t, int32_t>(value, volume) >> 12); } /* Required for floating point volume. Some are needed for compilation but * are not needed in execution and should be removed from the final build by * an optimizing compiler. */ template <> inline float MixMul<float, float, float>(float value, float volume) { return value * volume; } template <> inline float MixMul<float, int16_t, float>(int16_t value, float volume) { static const float float_from_q_15 = 1. / (1 << 15); return value * volume * float_from_q_15; } template <> inline int32_t MixMul<int32_t, int32_t, float>(int32_t value, float volume) { LOG_ALWAYS_FATAL("MixMul<int32_t, int32_t, float> Runtime Should not be here"); return value * volume; } template <> inline int32_t MixMul<int32_t, int16_t, float>(int16_t value, float volume) { LOG_ALWAYS_FATAL("MixMul<int32_t, int16_t, float> Runtime Should not be here"); static const float u4_12_from_float = (1 << 12); return value * volume * u4_12_from_float; } template <> inline int16_t MixMul<int16_t, int16_t, float>(int16_t value, float volume) { LOG_ALWAYS_FATAL("MixMul<int16_t, int16_t, float> Runtime Should not be here"); return value * volume; } template <> inline int16_t MixMul<int16_t, float, float>(float value, float volume) { static const float q_15_from_float = (1 << 15); return value * volume * q_15_from_float; } /* * MixAccum is used to add into an accumulator register of a possibly different * type. The TO and TI types are the same as MixMul. Loading services/audioflinger/AudioResampler.cpp +8 −4 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <sys/types.h> #include <cutils/log.h> #include <cutils/properties.h> #include <audio_utils/primitives.h> #include "AudioResampler.h" #include "AudioResamplerSinc.h" #include "AudioResamplerCubic.h" Loading Loading @@ -266,8 +267,9 @@ AudioResampler::AudioResampler(int inChannelCount, mPhaseFraction(0), mLocalTimeFreq(0), mPTS(AudioBufferProvider::kInvalidPTS), mQuality(quality) { const int maxChannels = quality < DYN_LOW_QUALITY ? 2 : 8; if (inChannelCount < 1 || inChannelCount > (quality < DYN_LOW_QUALITY ? 2 : 8)) { || inChannelCount > maxChannels) { LOG_ALWAYS_FATAL("Unsupported sample format %d quality %d channels", quality, inChannelCount); } Loading Loading @@ -297,10 +299,12 @@ void AudioResampler::setSampleRate(int32_t inSampleRate) { mPhaseIncrement = (uint32_t)((kPhaseMultiplier * inSampleRate) / mSampleRate); } void AudioResampler::setVolume(int16_t left, int16_t right) { void AudioResampler::setVolume(float left, float right) { // TODO: Implement anti-zipper filter mVolume[0] = left; mVolume[1] = right; // convert to U4.12 for internal integer use (round down) // integer volume values are clamped to 0 to UNITY_GAIN. mVolume[0] = u4_12_from_float(clampFloatVol(left)); mVolume[1] = u4_12_from_float(clampFloatVol(right)); } void AudioResampler::setLocalTimeFreq(uint64_t freq) { Loading Loading
services/audioflinger/Android.mk +3 −0 Original line number Diff line number Diff line Loading @@ -115,6 +115,9 @@ LOCAL_SRC_FILES:= \ AudioResamplerSinc.cpp.arm \ AudioResamplerDyn.cpp.arm LOCAL_C_INCLUDES := \ $(call include-path-for, audio-utils) LOCAL_SHARED_LIBRARIES := \ libcutils \ libdl \ Loading
services/audioflinger/AudioMixer.cpp +172 −70 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <stdint.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <sys/types.h> #include <utils/Errors.h> Loading Loading @@ -293,17 +294,32 @@ int AudioMixer::getTrackName(audio_channel_mask_t channelMask, // assume default parameters for the track, except where noted below track_t* t = &mState.tracks[n]; t->needs = 0; // Integer volume. // Currently integer volume is kept for the legacy integer mixer. // Will be removed when the legacy mixer path is removed. t->volume[0] = UNITY_GAIN_INT; t->volume[1] = UNITY_GAIN_INT; // no initialization needed // t->prevVolume[0] // t->prevVolume[1] t->prevVolume[0] = UNITY_GAIN_INT << 16; t->prevVolume[1] = UNITY_GAIN_INT << 16; t->volumeInc[0] = 0; t->volumeInc[1] = 0; t->auxLevel = 0; t->auxInc = 0; t->prevAuxLevel = 0; // Floating point volume. t->mVolume[0] = UNITY_GAIN_FLOAT; t->mVolume[1] = UNITY_GAIN_FLOAT; t->mPrevVolume[0] = UNITY_GAIN_FLOAT; t->mPrevVolume[1] = UNITY_GAIN_FLOAT; t->mVolumeInc[0] = 0.; t->mVolumeInc[1] = 0.; t->mAuxLevel = 0.; t->mAuxInc = 0.; t->mPrevAuxLevel = 0.; // no initialization needed // t->prevAuxLevel // t->frameCount t->channelCount = audio_channel_count_from_out_mask(channelMask); t->enabled = false; Loading Loading @@ -574,39 +590,68 @@ void AudioMixer::disable(int name) /* Sets the volume ramp variables for the AudioMixer. * * The volume ramp variables are used to transition between the previous * volume to the target volume. The duration of the transition is * set by ramp, which is either 0 for immediate, or typically one state * framecount period. * The volume ramp variables are used to transition from the previous * volume to the set volume. ramp controls the duration of the transition. * Its value is typically one state framecount period, but may also be 0, * meaning "immediate." * * FIXME: 1) Volume ramp is enabled only if there is a nonzero integer increment * even if there is a nonzero floating point increment (in that case, the volume * change is immediate). This restriction should be changed when the legacy mixer * is removed (see #2). * FIXME: 2) Integer volume variables are used for Legacy mixing and should be removed * when no longer needed. * * @param newFloatValue new volume target in float [0.0, 1.0]. * @param ramp number of frames to increment over. ramp is 0 if the volume * should be set immediately. * @param volume reference to the U4.12 target volume, set on return. * @param prevVolume reference to the U4.27 previous volume, set on return. * @param volumeInc reference to the increment per output audio frame, set on return. * @param newVolume set volume target in floating point [0.0, 1.0]. * @param ramp number of frames to increment over. if ramp is 0, the volume * should be set immediately. Currently ramp should not exceed 65535 (frames). * @param pIntSetVolume pointer to the U4.12 integer target volume, set on return. * @param pIntPrevVolume pointer to the U4.28 integer previous volume, set on return. * @param pIntVolumeInc pointer to the U4.28 increment per output audio frame, set on return. * @param pSetVolume pointer to the float target volume, set on return. * @param pPrevVolume pointer to the float previous volume, set on return. * @param pVolumeInc pointer to the float increment per output audio frame, set on return. * @return true if the volume has changed, false if volume is same. */ static inline bool setVolumeRampVariables(float newFloatValue, int32_t ramp, int16_t &volume, int32_t &prevVolume, int32_t &volumeInc) { int32_t newValue = newFloatValue * AudioMixer::UNITY_GAIN_INT; if (newValue > AudioMixer::UNITY_GAIN_INT) { newValue = AudioMixer::UNITY_GAIN_INT; } else if (newValue < 0) { ALOGE("negative volume %.7g", newFloatValue); newValue = 0; // should never happen, but for safety check. } if (newValue == volume) { static inline bool setVolumeRampVariables(float newVolume, int32_t ramp, int16_t *pIntSetVolume, int32_t *pIntPrevVolume, int32_t *pIntVolumeInc, float *pSetVolume, float *pPrevVolume, float *pVolumeInc) { if (newVolume == *pSetVolume) { return false; } /* set the floating point volume variables */ if (ramp != 0) { *pVolumeInc = (newVolume - *pSetVolume) / ramp; *pPrevVolume = *pSetVolume; } else { *pVolumeInc = 0; *pPrevVolume = newVolume; } *pSetVolume = newVolume; /* set the legacy integer volume variables */ int32_t intVolume = newVolume * AudioMixer::UNITY_GAIN_INT; if (intVolume > AudioMixer::UNITY_GAIN_INT) { intVolume = AudioMixer::UNITY_GAIN_INT; } else if (intVolume < 0) { ALOGE("negative volume %.7g", newVolume); intVolume = 0; // should never happen, but for safety check. } if (intVolume == *pIntSetVolume) { *pIntVolumeInc = 0; /* TODO: integer/float workaround: ignore floating volume ramp */ *pVolumeInc = 0; *pPrevVolume = newVolume; return true; } if (ramp != 0) { volumeInc = ((newValue - volume) << 16) / ramp; prevVolume = (volumeInc == 0 ? newValue : volume) << 16; *pIntVolumeInc = ((intVolume - *pIntSetVolume) << 16) / ramp; *pIntPrevVolume = (*pIntVolumeInc == 0 ? intVolume : *pIntSetVolume) << 16; } else { volumeInc = 0; prevVolume = newValue << 16; *pIntVolumeInc = 0; *pIntPrevVolume = intVolume << 16; } volume = newValue; *pIntSetVolume = intVolume; return true; } Loading Loading @@ -716,8 +761,10 @@ void AudioMixer::setParameter(int name, int target, int param, void *value) case VOLUME1: if (setVolumeRampVariables(*reinterpret_cast<float*>(value), target == RAMP_VOLUME ? mState.frameCount : 0, track.volume[param - VOLUME0], track.prevVolume[param - VOLUME0], track.volumeInc[param - VOLUME0])) { &track.volume[param - VOLUME0], &track.prevVolume[param - VOLUME0], &track.volumeInc[param - VOLUME0], &track.mVolume[param - VOLUME0], &track.mPrevVolume[param - VOLUME0], &track.mVolumeInc[param - VOLUME0])) { ALOGV("setParameter(%s, VOLUME%d: %04x)", target == VOLUME ? "VOLUME" : "RAMP_VOLUME", param - VOLUME0, track.volume[param - VOLUME0]); Loading @@ -725,10 +772,10 @@ void AudioMixer::setParameter(int name, int target, int param, void *value) } break; case AUXLEVEL: //ALOG_ASSERT(0 <= valueInt && valueInt <= MAX_GAIN_INT, "bad aux level %d", valueInt); if (setVolumeRampVariables(*reinterpret_cast<float*>(value), target == RAMP_VOLUME ? mState.frameCount : 0, track.auxLevel, track.prevAuxLevel, track.auxInc)) { &track.auxLevel, &track.prevAuxLevel, &track.auxInc, &track.mAuxLevel, &track.mPrevAuxLevel, &track.mAuxInc)) { ALOGV("setParameter(%s, AUXLEVEL: %04x)", target == VOLUME ? "VOLUME" : "RAMP_VOLUME", track.auxLevel); invalidateState(1 << name); Loading Loading @@ -777,21 +824,58 @@ bool AudioMixer::track_t::setResampler(uint32_t value, uint32_t devSampleRate) return false; } inline void AudioMixer::track_t::adjustVolumeRamp(bool aux) /* Checks to see if the volume ramp has completed and clears the increment * variables appropriately. * * FIXME: There is code to handle int/float ramp variable switchover should it not * complete within a mixer buffer processing call, but it is preferred to avoid switchover * due to precision issues. The switchover code is included for legacy code purposes * and can be removed once the integer volume is removed. * * It is not sufficient to clear only the volumeInc integer variable because * if one channel requires ramping, all channels are ramped. * * There is a bit of duplicated code here, but it keeps backward compatibility. */ inline void AudioMixer::track_t::adjustVolumeRamp(bool aux, bool useFloat) { if (useFloat) { for (uint32_t i=0 ; i<MAX_NUM_CHANNELS ; i++) { if (mVolumeInc[i] != 0 && fabs(mVolume[i] - mPrevVolume[i]) <= fabs(mVolumeInc[i])) { volumeInc[i] = 0; prevVolume[i] = volume[i] << 16; mVolumeInc[i] = 0.; mPrevVolume[i] = mVolume[i]; } else { //ALOGV("ramp: %f %f %f", mVolume[i], mPrevVolume[i], mVolumeInc[i]); prevVolume[i] = u4_28_from_float(mPrevVolume[i]); } } } else { for (uint32_t i=0 ; i<MAX_NUM_CHANNELS ; i++) { if (((volumeInc[i]>0) && (((prevVolume[i]+volumeInc[i])>>16) >= volume[i])) || ((volumeInc[i]<0) && (((prevVolume[i]+volumeInc[i])>>16) <= volume[i]))) { volumeInc[i] = 0; prevVolume[i] = volume[i] << 16; mVolumeInc[i] = 0.; mPrevVolume[i] = mVolume[i]; } else { //ALOGV("ramp: %d %d %d", volume[i] << 16, prevVolume[i], volumeInc[i]); mPrevVolume[i] = float_from_u4_28(prevVolume[i]); } } } /* TODO: aux is always integer regardless of output buffer type */ if (aux) { if (((auxInc>0) && (((prevAuxLevel+auxInc)>>16) >= auxLevel)) || ((auxInc<0) && (((prevAuxLevel+auxInc)>>16) <= auxLevel))) { auxInc = 0; prevAuxLevel = auxLevel << 16; mAuxInc = 0.; mPrevAuxLevel = mAuxLevel; } else { //ALOGV("aux ramp: %d %d %d", auxLevel << 16, prevAuxLevel, auxInc); } } } Loading Loading @@ -985,7 +1069,7 @@ void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFram // always resample with unity gain when sending to auxiliary buffer to be able // to apply send level after resampling // TODO: modify each resampler to support aux channel? t->resampler->setVolume(UNITY_GAIN_INT, UNITY_GAIN_INT); t->resampler->setVolume(UNITY_GAIN_FLOAT, UNITY_GAIN_FLOAT); memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t)); t->resampler->resample(temp, outFrameCount, t->bufferProvider); if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc)) { Loading @@ -995,7 +1079,7 @@ void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFram } } else { if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1])) { t->resampler->setVolume(UNITY_GAIN_INT, UNITY_GAIN_INT); t->resampler->setVolume(UNITY_GAIN_FLOAT, UNITY_GAIN_FLOAT); memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t)); t->resampler->resample(temp, outFrameCount, t->bufferProvider); volumeRampStereo(t, out, outFrameCount, temp, aux); Loading @@ -1003,7 +1087,7 @@ void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFram // constant gain else { t->resampler->setVolume(t->volume[0], t->volume[1]); t->resampler->setVolume(t->mVolume[0], t->mVolume[1]); t->resampler->resample(out, outFrameCount, t->bufferProvider); } } Loading Loading @@ -1721,6 +1805,36 @@ int64_t AudioMixer::calculateOutputPTS(const track_t& t, int64_t basePTS, ALOGW_IF(!sIsMultichannelCapable, "unable to find downmix effect"); } template <int MIXTYPE, int NCHAN, bool USEFLOATVOL, bool ADJUSTVOL, typename TO, typename TI, typename TA> void AudioMixer::volumeMix(TO *out, size_t outFrames, const TI *in, TA *aux, bool ramp, AudioMixer::track_t *t) { if (USEFLOATVOL) { if (ramp) { volumeRampMulti<MIXTYPE, NCHAN>(out, outFrames, in, aux, t->mPrevVolume, t->mVolumeInc, &t->prevAuxLevel, t->auxInc); if (ADJUSTVOL) { t->adjustVolumeRamp(aux != NULL, true); } } else { volumeMulti<MIXTYPE, NCHAN>(out, outFrames, in, aux, t->mVolume, t->auxLevel); } } else { if (ramp) { volumeRampMulti<MIXTYPE, NCHAN>(out, outFrames, in, aux, t->prevVolume, t->volumeInc, &t->prevAuxLevel, t->auxInc); if (ADJUSTVOL) { t->adjustVolumeRamp(aux != NULL); } } else { volumeMulti<MIXTYPE, NCHAN>(out, outFrames, in, aux, t->volume, t->auxLevel); } } } /* This process hook is called when there is a single track without * aux buffer, volume ramp, or resampling. * TODO: Update the hook selection: this can properly handle aux and ramp. Loading Loading @@ -1757,13 +1871,9 @@ void AudioMixer::process_NoResampleOneTrack(state_t* state, int64_t pts) } const size_t outFrames = b.frameCount; if (ramp) { volumeRampMulti<MIXTYPE_MULTI_SAVEONLY, NCHAN>(out, outFrames, in, aux, t->prevVolume, t->volumeInc, &t->prevAuxLevel, t->auxInc); } else { volumeMulti<MIXTYPE_MULTI_SAVEONLY, NCHAN>(out, outFrames, in, aux, t->volume, t->auxLevel); } volumeMix<MIXTYPE, NCHAN, is_same<TI, float>::value, false> (out, outFrames, in, aux, ramp, t); out += outFrames * NCHAN; if (aux != NULL) { aux += NCHAN; Loading @@ -1774,7 +1884,7 @@ void AudioMixer::process_NoResampleOneTrack(state_t* state, int64_t pts) t->bufferProvider->releaseBuffer(&b); } if (ramp) { t->adjustVolumeRamp(aux != NULL); t->adjustVolumeRamp(aux != NULL, is_same<TI, float>::value); } } Loading @@ -1792,19 +1902,15 @@ void AudioMixer::track__Resample(track_t* t, TO* out, size_t outFrameCount, TO* // if ramp: resample with unity gain to temp buffer and scale/mix in 2nd step. // if aux != NULL: resample with unity gain to temp buffer then apply send level. t->resampler->setVolume(UNITY_GAIN_INT, UNITY_GAIN_INT); t->resampler->setVolume(UNITY_GAIN_FLOAT, UNITY_GAIN_FLOAT); memset(temp, 0, outFrameCount * NCHAN * sizeof(TO)); t->resampler->resample((int32_t*)temp, outFrameCount, t->bufferProvider); if (ramp) { volumeRampMulti<MIXTYPE_MULTI, NCHAN>(out, outFrameCount, temp, aux, t->prevVolume, t->volumeInc, &t->prevAuxLevel, t->auxInc); t->adjustVolumeRamp(aux != NULL); } else { volumeMulti<MIXTYPE_MULTI, NCHAN>(out, outFrameCount, temp, aux, t->volume, t->auxLevel); } volumeMix<MIXTYPE, NCHAN, is_same<TI, float>::value, true>(out, outFrameCount, temp, aux, ramp, t); } else { // constant volume gain t->resampler->setVolume(t->volume[0], t->volume[1]); t->resampler->setVolume(t->mVolume[0], t->mVolume[1]); t->resampler->resample((int32_t*)out, outFrameCount, t->bufferProvider); } } Loading @@ -1819,13 +1925,9 @@ void AudioMixer::track__NoResample(track_t* t, TO* out, size_t frameCount, ALOGVV("track__NoResample\n"); const TI *in = static_cast<const TI *>(t->in); if (t->needsRamp()) { volumeRampMulti<MIXTYPE, NCHAN>(out, frameCount, in, aux, t->prevVolume, t->volumeInc, &t->prevAuxLevel, t->auxInc); t->adjustVolumeRamp(aux != NULL); } else { volumeMulti<MIXTYPE, NCHAN>(out, frameCount, in, aux, t->volume, t->auxLevel); } volumeMix<MIXTYPE, NCHAN, is_same<TI, float>::value, true>(out, frameCount, in, aux, t->needsRamp(), t); // MIXTYPE_MONOEXPAND reads a single input channel and expands to NCHAN output channels. // MIXTYPE_MULTI reads NCHAN input channels and places to NCHAN output channels. in += (MIXTYPE == MIXTYPE_MONOEXPAND) ? frameCount : frameCount * NCHAN; Loading
services/audioflinger/AudioMixer.h +26 −3 Original line number Diff line number Diff line Loading @@ -163,8 +163,9 @@ private: struct track_t { uint32_t needs; // TODO: Eventually remove legacy integer volume settings union { int16_t volume[MAX_NUM_CHANNELS]; // [0]3.12 fixed point int16_t volume[MAX_NUM_CHANNELS]; // U4.12 fixed point (top bit should be zero) int32_t volumeRL; }; Loading Loading @@ -217,7 +218,13 @@ private: audio_format_t mMixerInFormat; // mix internal format AUDIO_FORMAT_PCM_(FLOAT|16_BIT) // each track must be converted to this format. int32_t mUnused[1]; // alignment padding float mVolume[MAX_NUM_CHANNELS]; // floating point set volume float mPrevVolume[MAX_NUM_CHANNELS]; // floating point previous volume float mVolumeInc[MAX_NUM_CHANNELS]; // floating point volume increment float mAuxLevel; // floating point set aux level float mPrevAuxLevel; // floating point prev aux level float mAuxInc; // floating point aux increment // 16-byte boundary Loading @@ -225,7 +232,7 @@ private: bool setResampler(uint32_t sampleRate, uint32_t devSampleRate); bool doesResample() const { return resampler != NULL; } void resetResampler() { if (resampler != NULL) resampler->reset(); } void adjustVolumeRamp(bool aux); void adjustVolumeRamp(bool aux, bool useFloat = false); size_t getUnreleasedFrames() const { return resampler != NULL ? resampler->getUnreleasedFrames() : 0; }; }; Loading Loading @@ -349,6 +356,22 @@ private: static pthread_once_t sOnceControl; static void sInitRoutine(); /* multi-format volume mixing function (calls template functions * in AudioMixerOps.h). The template parameters are as follows: * * MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration) * NCHAN (number of channels, 2 for now) * USEFLOATVOL (set to true if float volume is used) * ADJUSTVOL (set to true if volume ramp parameters needs adjustment afterwards) * TO: int32_t (Q4.27) or float * TI: int32_t (Q4.27) or int16_t (Q0.15) or float * TA: int32_t (Q4.27) */ template <int MIXTYPE, int NCHAN, bool USEFLOATVOL, bool ADJUSTVOL, typename TO, typename TI, typename TA> static void volumeMix(TO *out, size_t outFrames, const TI *in, TA *aux, bool ramp, AudioMixer::track_t *t); // multi-format process hooks template <int MIXTYPE, int NCHAN, typename TO, typename TI, typename TA> static void process_NoResampleOneTrack(state_t* state, int64_t pts); Loading
services/audioflinger/AudioMixerOps.h +40 −0 Original line number Diff line number Diff line Loading @@ -136,6 +136,46 @@ inline int16_t MixMul<int16_t, int32_t, int32_t>(int32_t value, int32_t volume) return clamp16(MixMul<int32_t, int32_t, int32_t>(value, volume) >> 12); } /* Required for floating point volume. Some are needed for compilation but * are not needed in execution and should be removed from the final build by * an optimizing compiler. */ template <> inline float MixMul<float, float, float>(float value, float volume) { return value * volume; } template <> inline float MixMul<float, int16_t, float>(int16_t value, float volume) { static const float float_from_q_15 = 1. / (1 << 15); return value * volume * float_from_q_15; } template <> inline int32_t MixMul<int32_t, int32_t, float>(int32_t value, float volume) { LOG_ALWAYS_FATAL("MixMul<int32_t, int32_t, float> Runtime Should not be here"); return value * volume; } template <> inline int32_t MixMul<int32_t, int16_t, float>(int16_t value, float volume) { LOG_ALWAYS_FATAL("MixMul<int32_t, int16_t, float> Runtime Should not be here"); static const float u4_12_from_float = (1 << 12); return value * volume * u4_12_from_float; } template <> inline int16_t MixMul<int16_t, int16_t, float>(int16_t value, float volume) { LOG_ALWAYS_FATAL("MixMul<int16_t, int16_t, float> Runtime Should not be here"); return value * volume; } template <> inline int16_t MixMul<int16_t, float, float>(float value, float volume) { static const float q_15_from_float = (1 << 15); return value * volume * q_15_from_float; } /* * MixAccum is used to add into an accumulator register of a possibly different * type. The TO and TI types are the same as MixMul. Loading
services/audioflinger/AudioResampler.cpp +8 −4 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <sys/types.h> #include <cutils/log.h> #include <cutils/properties.h> #include <audio_utils/primitives.h> #include "AudioResampler.h" #include "AudioResamplerSinc.h" #include "AudioResamplerCubic.h" Loading Loading @@ -266,8 +267,9 @@ AudioResampler::AudioResampler(int inChannelCount, mPhaseFraction(0), mLocalTimeFreq(0), mPTS(AudioBufferProvider::kInvalidPTS), mQuality(quality) { const int maxChannels = quality < DYN_LOW_QUALITY ? 2 : 8; if (inChannelCount < 1 || inChannelCount > (quality < DYN_LOW_QUALITY ? 2 : 8)) { || inChannelCount > maxChannels) { LOG_ALWAYS_FATAL("Unsupported sample format %d quality %d channels", quality, inChannelCount); } Loading Loading @@ -297,10 +299,12 @@ void AudioResampler::setSampleRate(int32_t inSampleRate) { mPhaseIncrement = (uint32_t)((kPhaseMultiplier * inSampleRate) / mSampleRate); } void AudioResampler::setVolume(int16_t left, int16_t right) { void AudioResampler::setVolume(float left, float right) { // TODO: Implement anti-zipper filter mVolume[0] = left; mVolume[1] = right; // convert to U4.12 for internal integer use (round down) // integer volume values are clamped to 0 to UNITY_GAIN. mVolume[0] = u4_12_from_float(clampFloatVol(left)); mVolume[1] = u4_12_from_float(clampFloatVol(right)); } void AudioResampler::setLocalTimeFreq(uint64_t freq) { Loading