Merge "Revert "Camera: Load initial session params speculatively"" into pi-dev
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index 5d0f68e..ad1ccbc 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -262,6 +262,17 @@
void CryptoHal::clearHeapBase(int32_t seqNum) {
Mutex::Autolock autoLock(mLock);
+ /*
+ * Clear the remote shared memory mapping by setting the shared
+ * buffer base to a null hidl_memory.
+ *
+ * TODO: Add a releaseSharedBuffer method in a future DRM HAL
+ * API version to make this explicit.
+ */
+ uint32_t bufferId = mHeapBases.valueFor(seqNum).getBufferId();
+ Return<void> hResult = mPlugin->setSharedBufferBase(hidl_memory(), bufferId);
+ ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
+
mHeapBases.removeItem(seqNum);
}
diff --git a/media/img_utils/src/DngUtils.cpp b/media/img_utils/src/DngUtils.cpp
index 67ec244..9ac7e2a 100644
--- a/media/img_utils/src/DngUtils.cpp
+++ b/media/img_utils/src/DngUtils.cpp
@@ -302,29 +302,14 @@
normalizedOCX = CLAMP(normalizedOCX, 0, 1);
normalizedOCY = CLAMP(normalizedOCY, 0, 1);
- // Conversion factors from Camera2 K factors to DNG spec. K factors:
- //
- // Note: these are necessary because our unit system assumes a
- // normalized max radius of sqrt(2), whereas the DNG spec's
- // WarpRectilinear opcode assumes a normalized max radius of 1.
- // Thus, each K coefficient must include the domain scaling
- // factor (the DNG domain is scaled by sqrt(2) to emulate the
- // domain used by the Camera2 specification).
-
- const double c_0 = sqrt(2);
- const double c_1 = 2 * sqrt(2);
- const double c_2 = 4 * sqrt(2);
- const double c_3 = 8 * sqrt(2);
- const double c_4 = 2;
- const double c_5 = 2;
-
- const double coeffs[] = { c_0 * kCoeffs[0],
- c_1 * kCoeffs[1],
- c_2 * kCoeffs[2],
- c_3 * kCoeffs[3],
- c_4 * kCoeffs[4],
- c_5 * kCoeffs[5] };
-
+ double coeffs[6] = {
+ kCoeffs[0],
+ kCoeffs[1],
+ kCoeffs[2],
+ kCoeffs[3],
+ kCoeffs[4],
+ kCoeffs[5]
+ };
return addWarpRectilinear(/*numPlanes*/1,
/*opticalCenterX*/normalizedOCX,
diff --git a/media/libaudioprocessing/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp
index aa39443..f6f817a 100644
--- a/media/libaudioprocessing/AudioMixer.cpp
+++ b/media/libaudioprocessing/AudioMixer.cpp
@@ -192,7 +192,6 @@
// always recompute for both channel masks even if only one has changed.
const uint32_t trackChannelCount = audio_channel_count_from_out_mask(trackChannelMask);
const uint32_t mixerChannelCount = audio_channel_count_from_out_mask(mixerChannelMask);
- const bool mixerChannelCountChanged = track->mMixerChannelCount != mixerChannelCount;
ALOG_ASSERT((trackChannelCount <= MAX_NUM_CHANNELS_TO_DOWNMIX)
&& trackChannelCount
@@ -213,7 +212,7 @@
// do it after downmix since track format may change!
track->prepareForReformat();
- if (track->mResampler.get() != nullptr && mixerChannelCountChanged) {
+ if (track->mResampler.get() != nullptr) {
// resampler channels may have changed.
const uint32_t resetToSampleRate = track->sampleRate;
track->mResampler.reset(nullptr);
diff --git a/media/libeffects/dynamicsproc/EffectDynamicsProcessing.cpp b/media/libeffects/dynamicsproc/EffectDynamicsProcessing.cpp
index 55383eb..0b883f1 100644
--- a/media/libeffects/dynamicsproc/EffectDynamicsProcessing.cpp
+++ b/media/libeffects/dynamicsproc/EffectDynamicsProcessing.cpp
@@ -51,7 +51,7 @@
{0x7261676f, 0x6d75, 0x7369, 0x6364, {0x28, 0xe2, 0xfd, 0x3a, 0xc3, 0x9e}}, // type
{0xe0e6539b, 0x1781, 0x7261, 0x676f, {0x6d, 0x75, 0x73, 0x69, 0x63, 0x40}}, // uuid
EFFECT_CONTROL_API_VERSION,
- (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST),
+ (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_LAST | EFFECT_FLAG_VOLUME_CTRL),
0, // TODO
1,
"Dynamics Processing",
@@ -367,6 +367,76 @@
return 0;
}
+//helper function
+bool DP_checkSizesInt(uint32_t paramSize, uint32_t valueSize, uint32_t expectedParams,
+ uint32_t expectedValues) {
+ if (paramSize < expectedParams * sizeof(int32_t)) {
+ ALOGE("Invalid paramSize: %u expected %u", paramSize,
+ (uint32_t)(expectedParams * sizeof(int32_t)));
+ return false;
+ }
+ if (valueSize < expectedValues * sizeof(int32_t)) {
+ ALOGE("Invalid valueSize %u expected %u", valueSize,
+ (uint32_t)(expectedValues * sizeof(int32_t)));
+ return false;
+ }
+ return true;
+}
+
+static dp_fx::DPChannel* DP_getChannel(DynamicsProcessingContext *pContext,
+ int32_t channel) {
+ if (pContext->mPDynamics == NULL) {
+ return NULL;
+ }
+ dp_fx::DPChannel *pChannel = pContext->mPDynamics->getChannel(channel);
+ ALOGE_IF(pChannel == NULL, "DPChannel NULL. invalid channel %d", channel);
+ return pChannel;
+}
+
+static dp_fx::DPEq* DP_getEq(DynamicsProcessingContext *pContext, int32_t channel,
+ int32_t eqType) {
+ dp_fx::DPChannel *pChannel = DP_getChannel(pContext, channel);
+ if (pChannel == NULL) {
+ return NULL;
+ }
+ dp_fx::DPEq *pEq = (eqType == DP_PARAM_PRE_EQ ? pChannel->getPreEq() :
+ (eqType == DP_PARAM_POST_EQ ? pChannel->getPostEq() : NULL));
+ ALOGE_IF(pEq == NULL,"DPEq NULL invalid eq");
+ return pEq;
+}
+
+static dp_fx::DPEqBand* DP_getEqBand(DynamicsProcessingContext *pContext, int32_t channel,
+ int32_t eqType, int32_t band) {
+ dp_fx::DPEq *pEq = DP_getEq(pContext, channel, eqType);
+ if (pEq == NULL) {
+ return NULL;
+ }
+ dp_fx::DPEqBand *pEqBand = pEq->getBand(band);
+ ALOGE_IF(pEqBand == NULL, "DPEqBand NULL. invalid band %d", band);
+ return pEqBand;
+}
+
+static dp_fx::DPMbc* DP_getMbc(DynamicsProcessingContext *pContext, int32_t channel) {
+ dp_fx::DPChannel * pChannel = DP_getChannel(pContext, channel);
+ if (pChannel == NULL) {
+ return NULL;
+ }
+ dp_fx::DPMbc *pMbc = pChannel->getMbc();
+ ALOGE_IF(pMbc == NULL, "DPMbc NULL invalid MBC");
+ return pMbc;
+}
+
+static dp_fx::DPMbcBand* DP_getMbcBand(DynamicsProcessingContext *pContext, int32_t channel,
+ int32_t band) {
+ dp_fx::DPMbc *pMbc = DP_getMbc(pContext, channel);
+ if (pMbc == NULL) {
+ return NULL;
+ }
+ dp_fx::DPMbcBand *pMbcBand = pMbc->getBand(band);
+ ALOGE_IF(pMbcBand == NULL, "pMbcBand NULL. invalid band %d", band);
+ return pMbcBand;
+}
+
int DP_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
void *pCmdData, uint32_t *replySize, void *pReplyData) {
@@ -483,8 +553,49 @@
p->data + voffset);
break;
}
+ case EFFECT_CMD_SET_VOLUME: {
+ ALOGV("EFFECT_CMD_SET_VOLUME");
+ // if pReplyData is NULL, VOL_CTRL is delegated to another effect
+ if (pReplyData == NULL || replySize == NULL || *replySize < ((int)sizeof(int32_t) * 2)) {
+ ALOGV("no VOLUME data to return");
+ break;
+ }
+ if (pCmdData == NULL || cmdSize < ((int)sizeof(uint32_t) * 2)) {
+ ALOGE("\tLVM_ERROR : DynamicsProcessing EFFECT_CMD_SET_VOLUME ERROR");
+ return -EINVAL;
+ }
+
+ const int32_t unityGain = 1 << 24;
+ //channel count
+ int32_t channelCount = (int32_t)audio_channel_count_from_out_mask(
+ pContext->mConfig.inputCfg.channels);
+ for (int32_t ch = 0; ch < channelCount; ch++) {
+
+ dp_fx::DPChannel * pChannel = DP_getChannel(pContext, ch);
+ if (pChannel == NULL) {
+ ALOGE("%s EFFECT_CMD_SET_VOLUME invalid channel %d", __func__, ch);
+ return -EINVAL;
+ break;
+ }
+
+ int32_t offset = ch;
+ if (ch > 1) {
+ // FIXME: limited to 2 unique channels. If more channels present, use value for
+ // first channel
+ offset = 0;
+ }
+ const float gain = (float)*((uint32_t *)pCmdData + offset) / unityGain;
+ const float gainDb = linearToDb(gain);
+ ALOGVV("%s EFFECT_CMD_SET_VOLUME channel %d, engine outputlevel %f (%0.2f dB)",
+ __func__, ch, gain, gainDb);
+ pChannel->setOutputGain(gainDb);
+ }
+
+ const int32_t volRet[2] = {unityGain, unityGain}; // Apply no volume before effect.
+ memcpy(pReplyData, volRet, sizeof(volRet));
+ break;
+ }
case EFFECT_CMD_SET_DEVICE:
- case EFFECT_CMD_SET_VOLUME:
case EFFECT_CMD_SET_AUDIO_MODE:
break;
@@ -523,76 +634,6 @@
return 0;
}
-//helper function
-bool DP_checkSizesInt(uint32_t paramSize, uint32_t valueSize, uint32_t expectedParams,
- uint32_t expectedValues) {
- if (paramSize < expectedParams * sizeof(int32_t)) {
- ALOGE("Invalid paramSize: %u expected %u", paramSize,
- (uint32_t) (expectedParams * sizeof(int32_t)));
- return false;
- }
- if (valueSize < expectedValues * sizeof(int32_t)) {
- ALOGE("Invalid valueSize %u expected %u", valueSize,
- (uint32_t)(expectedValues * sizeof(int32_t)));
- return false;
- }
- return true;
-}
-
-static dp_fx::DPChannel* DP_getChannel(DynamicsProcessingContext *pContext,
- int32_t channel) {
- if (pContext->mPDynamics == NULL) {
- return NULL;
- }
- dp_fx::DPChannel *pChannel = pContext->mPDynamics->getChannel(channel);
- ALOGE_IF(pChannel == NULL, "DPChannel NULL. invalid channel %d", channel);
- return pChannel;
-}
-
-static dp_fx::DPEq* DP_getEq(DynamicsProcessingContext *pContext, int32_t channel,
- int32_t eqType) {
- dp_fx::DPChannel * pChannel = DP_getChannel(pContext, channel);
- if (pChannel == NULL) {
- return NULL;
- }
- dp_fx::DPEq *pEq = (eqType == DP_PARAM_PRE_EQ ? pChannel->getPreEq() :
- (eqType == DP_PARAM_POST_EQ ? pChannel->getPostEq() : NULL));
- ALOGE_IF(pEq == NULL,"DPEq NULL invalid eq");
- return pEq;
-}
-
-static dp_fx::DPEqBand* DP_getEqBand(DynamicsProcessingContext *pContext, int32_t channel,
- int32_t eqType, int32_t band) {
- dp_fx::DPEq *pEq = DP_getEq(pContext, channel, eqType);
- if (pEq == NULL) {
- return NULL;
- }
- dp_fx::DPEqBand *pEqBand = pEq->getBand(band);
- ALOGE_IF(pEqBand == NULL, "DPEqBand NULL. invalid band %d", band);
- return pEqBand;
-}
-
-static dp_fx::DPMbc* DP_getMbc(DynamicsProcessingContext *pContext, int32_t channel) {
- dp_fx::DPChannel * pChannel = DP_getChannel(pContext, channel);
- if (pChannel == NULL) {
- return NULL;
- }
- dp_fx::DPMbc *pMbc = pChannel->getMbc();
- ALOGE_IF(pMbc == NULL, "DPMbc NULL invalid MBC");
- return pMbc;
-}
-
-static dp_fx::DPMbcBand* DP_getMbcBand(DynamicsProcessingContext *pContext, int32_t channel,
- int32_t band) {
- dp_fx::DPMbc *pMbc = DP_getMbc(pContext, channel);
- if (pMbc == NULL) {
- return NULL;
- }
- dp_fx::DPMbcBand *pMbcBand = pMbc->getBand(band);
- ALOGE_IF(pMbcBand == NULL, "pMbcBand NULL. invalid band %d", band);
- return pMbcBand;
-}
-
int DP_getParameter(DynamicsProcessingContext *pContext,
uint32_t paramSize,
void *pParam,
diff --git a/media/libeffects/dynamicsproc/dsp/DPBase.cpp b/media/libeffects/dynamicsproc/dsp/DPBase.cpp
index 8b79991..ac758e0 100644
--- a/media/libeffects/dynamicsproc/dsp/DPBase.cpp
+++ b/media/libeffects/dynamicsproc/dsp/DPBase.cpp
@@ -174,8 +174,8 @@
}
//----
-DPChannel::DPChannel() : mInitialized(false), mInputGainDb(0), mPreEqInUse(false), mMbcInUse(false),
- mPostEqInUse(false), mLimiterInUse(false) {
+DPChannel::DPChannel() : mInitialized(false), mInputGainDb(0), mOutputGainDb(0),
+ mPreEqInUse(false), mMbcInUse(false), mPostEqInUse(false), mLimiterInUse(false) {
}
void DPChannel::init(float inputGain, bool preEqInUse, uint32_t preEqBandCount,
diff --git a/media/libeffects/dynamicsproc/dsp/DPBase.h b/media/libeffects/dynamicsproc/dsp/DPBase.h
index 355f64b..e74f91d 100644
--- a/media/libeffects/dynamicsproc/dsp/DPBase.h
+++ b/media/libeffects/dynamicsproc/dsp/DPBase.h
@@ -272,6 +272,16 @@
mInputGainDb = gain;
}
+ float getOutputGain() const {
+ if (!mInitialized) {
+ return 0;
+ }
+ return mOutputGainDb;
+ }
+ void setOutputGain(float gain) {
+ mOutputGainDb = gain;
+ }
+
DPEq* getPreEq();
DPMbc* getMbc();
DPEq* getPostEq();
@@ -281,6 +291,7 @@
private:
bool mInitialized;
float mInputGainDb;
+ float mOutputGainDb;
DPEq mPreEq;
DPMbc mMbc;
diff --git a/media/libeffects/dynamicsproc/dsp/DPFrequency.cpp b/media/libeffects/dynamicsproc/dsp/DPFrequency.cpp
index 59195fc..d06fd70 100644
--- a/media/libeffects/dynamicsproc/dsp/DPFrequency.cpp
+++ b/media/libeffects/dynamicsproc/dsp/DPFrequency.cpp
@@ -29,7 +29,7 @@
#define CIRCULAR_BUFFER_UPSAMPLE 4 //4 times buffer size
-static constexpr float MIN_ENVELOPE = 0.000001f;
+static constexpr float MIN_ENVELOPE = 1e-6f; //-120 dB
//helper functionS
static inline bool isPowerOf2(unsigned long n) {
return (n & (n - 1)) == 0;
@@ -53,14 +53,6 @@
#define IS_CHANGED(c, a, b) { c |= !compareEquality(a,b); \
(a) = (b); }
-float dBtoLinear(float valueDb) {
- return pow (10, valueDb / 20.0);
-}
-
-float linearToDb(float value) {
- return 20 * log10(value);
-}
-
//ChannelBuffers helper
void ChannelBuffer::initBuffers(unsigned int blockSize, unsigned int overlapSize,
unsigned int halfFftSize, unsigned int samplingRate, DPBase &dpBase) {
@@ -74,7 +66,7 @@
cBOutput.resize(mBlockSize * CIRCULAR_BUFFER_UPSAMPLE);
//fill input with half block size...
- for (unsigned int k = 0; k < mBlockSize/2; k++) {
+ for (unsigned int k = 0; k < mBlockSize/2; k++) {
cBInput.write(0);
}
@@ -94,12 +86,14 @@
mMbcBands.size(), mPostEqBands.size());
DPChannel *pChannel = dpBase.getChannel(0);
- if (pChannel != NULL) {
+ if (pChannel != nullptr) {
mPreEqInUse = pChannel->getPreEq()->isInUse();
mMbcInUse = pChannel->getMbc()->isInUse();
mPostEqInUse = pChannel->getPostEq()->isInUse();
mLimiterInUse = pChannel->getLimiter()->isInUse();
}
+
+ mLimiterParams.linkGroup = -1; //no group.
}
void ChannelBuffer::computeBinStartStop(BandParams &bp, size_t binStart) {
@@ -108,8 +102,35 @@
bp.binStop = (int)(0.5 + bp.freqCutoffHz * mBlockSize / mSamplingRate);
}
-//== DPFrequency
+//== LinkedLimiters Helper
+void LinkedLimiters::reset() {
+ mGroupsMap.clear();
+}
+void LinkedLimiters::update(int32_t group, int index) {
+ mGroupsMap[group].push_back(index);
+}
+
+void LinkedLimiters::remove(int index) {
+ //check all groups and if index is found, remove it.
+ //if group is empty afterwards, remove it.
+ for (auto it = mGroupsMap.begin(); it != mGroupsMap.end(); ) {
+ for (auto itIndex = it->second.begin(); itIndex != it->second.end(); ) {
+ if (*itIndex == index) {
+ itIndex = it->second.erase(itIndex);
+ } else {
+ ++itIndex;
+ }
+ }
+ if (it->second.size() == 0) {
+ it = mGroupsMap.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+//== DPFrequency
void DPFrequency::reset() {
}
@@ -147,14 +168,25 @@
mSamplingRate, *this);
}
- //dsp
+ //effective number of frames processed per second
+ mBlocksPerSecond = (float)mSamplingRate / (mBlockSize - mOverlapSize);
+
fill_window(mVWindow, RDSP_WINDOW_HANNING_FLAT_TOP, mBlockSize, mOverlapSize);
+
+ //compute window rms for energy compensation
+ mWindowRms = 0;
+ for (size_t i = 0; i < mVWindow.size(); i++) {
+ mWindowRms += mVWindow[i] * mVWindow[i];
+ }
+
+ //Making sure window rms is not zero.
+ mWindowRms = std::max(sqrt(mWindowRms / mVWindow.size()), MIN_ENVELOPE);
}
void DPFrequency::updateParameters(ChannelBuffer &cb, int channelIndex) {
DPChannel *pChannel = getChannel(channelIndex);
- if (pChannel == NULL) {
+ if (pChannel == nullptr) {
ALOGE("Error: updateParameters null DPChannel %d", channelIndex);
return;
}
@@ -166,7 +198,7 @@
//===EqPre
if (cb.mPreEqInUse) {
DPEq *pPreEq = pChannel->getPreEq();
- if (pPreEq == NULL) {
+ if (pPreEq == nullptr) {
ALOGE("Error: updateParameters null PreEq for channel: %d", channelIndex);
return;
}
@@ -174,7 +206,7 @@
if (cb.mPreEqEnabled) {
for (unsigned int b = 0; b < getPreEqBandCount(); b++) {
DPEqBand *pEqBand = pPreEq->getBand(b);
- if (pEqBand == NULL) {
+ if (pEqBand == nullptr) {
ALOGE("Error: updateParameters null PreEqBand for band %d", b);
return; //failed.
}
@@ -222,7 +254,7 @@
bool changed = false;
DPEq *pPostEq = pChannel->getPostEq();
- if (pPostEq == NULL) {
+ if (pPostEq == nullptr) {
ALOGE("Error: updateParameters null postEq for channel: %d", channelIndex);
return; //failed.
}
@@ -230,7 +262,7 @@
if (cb.mPostEqEnabled) {
for (unsigned int b = 0; b < getPostEqBandCount(); b++) {
DPEqBand *pEqBand = pPostEq->getBand(b);
- if (pEqBand == NULL) {
+ if (pEqBand == nullptr) {
ALOGE("Error: updateParameters PostEqBand NULL for band %d", b);
return; //failed.
}
@@ -265,7 +297,7 @@
//===MBC
if (cb.mMbcInUse) {
DPMbc *pMbc = pChannel->getMbc();
- if (pMbc == NULL) {
+ if (pMbc == nullptr) {
ALOGE("Error: updateParameters Mbc NULL for channel: %d", channelIndex);
return;
}
@@ -274,7 +306,7 @@
bool changed = false;
for (unsigned int b = 0; b < getMbcBandCount(); b++) {
DPMbcBand *pMbcBand = pMbc->getBand(b);
- if (pMbcBand == NULL) {
+ if (pMbcBand == nullptr) {
ALOGE("Error: updateParameters MbcBand NULL for band %d", b);
return; //failed.
}
@@ -307,11 +339,38 @@
cb.computeBinStartStop(*pMbcBandParams, binNext);
binNext = pMbcBandParams->binStop + 1;
}
-
}
-
}
}
+
+ //===Limiter
+ if (cb.mLimiterInUse) {
+ bool changed = false;
+ DPLimiter *pLimiter = pChannel->getLimiter();
+ if (pLimiter == nullptr) {
+ ALOGE("Error: updateParameters Limiter NULL for channel: %d", channelIndex);
+ return;
+ }
+ cb.mLimiterEnabled = pLimiter->isEnabled();
+ if (cb.mLimiterEnabled) {
+ IS_CHANGED(changed, cb.mLimiterParams.linkGroup ,
+ (int32_t)pLimiter->getLinkGroup());
+ cb.mLimiterParams.attackTimeMs = pLimiter->getAttackTime();
+ cb.mLimiterParams.releaseTimeMs = pLimiter->getReleaseTime();
+ cb.mLimiterParams.ratio = pLimiter->getRatio();
+ cb.mLimiterParams.thresholdDb = pLimiter->getThreshold();
+ cb.mLimiterParams.postGainDb = pLimiter->getPostGain();
+ }
+
+ if (changed) {
+ ALOGV("limiter changed, recomputing linkGroups for %d", channelIndex);
+ mLinkedLimiters.remove(channelIndex); //in case it was already there.
+ mLinkedLimiters.update(cb.mLimiterParams.linkGroup, channelIndex);
+ }
+ }
+
+ //=== Output Gain
+ cb.outputGainDb = pChannel->getOutputGain();
}
size_t DPFrequency::processSamples(const float *in, float *out, size_t samples) {
@@ -336,12 +395,8 @@
}
}
- //TODO: lookahead limiters
- //TODO: apply linked limiters to all channels.
- //**Process each Channel
- for (int ch = 0; ch < channelCount; ch++) {
- processMono(mChannelBuffers[ch]);
- }
+ //**process all channelBuffers
+ processChannelBuffers(mChannelBuffers);
//** estimate how much data is available in ALL channels
size_t available = mChannelBuffers[0].cBOutput.availableToRead();
@@ -370,62 +425,78 @@
return samples;
}
-size_t DPFrequency::processMono(ChannelBuffer &cb) {
-
+size_t DPFrequency::processChannelBuffers(CBufferVector &channelBuffers) {
+ const int channelCount = channelBuffers.size();
size_t processedSamples = 0;
+ size_t processFrames = mBlockSize - mOverlapSize;
- size_t available = cb.cBInput.availableToRead();
- while (available >= mBlockSize - mOverlapSize) {
-
- //move tail of previous
- for (unsigned int k = 0; k < mOverlapSize; ++k) {
- cb.input[k] = cb.input[mBlockSize - mOverlapSize + k];
- }
-
- //read new available data
- for (unsigned int k = 0; k < mBlockSize - mOverlapSize; k++) {
- cb.input[mOverlapSize + k] = cb.cBInput.read();
- }
-
- //## Actual process
- processOneVector(cb.output, cb.input, cb);
- //##End of Process
-
- //mix tail (and capture new tail
- for (unsigned int k = 0; k < mOverlapSize; k++) {
- cb.output[k] += cb.outTail[k];
- cb.outTail[k] = cb.output[mBlockSize - mOverlapSize + k]; //new tail
- }
-
- //output data
- for (unsigned int k = 0; k < mBlockSize - mOverlapSize; k++) {
- cb.cBOutput.write(cb.output[k]);
- }
-
- available = cb.cBInput.availableToRead();
+ size_t available = channelBuffers[0].cBInput.availableToRead();
+ for (int ch = 1; ch < channelCount; ch++) {
+ available = std::min(available, channelBuffers[ch].cBInput.availableToRead());
}
+ while (available >= processFrames) {
+ //First pass
+ for (int ch = 0; ch < channelCount; ch++) {
+ ChannelBuffer * pCb = &channelBuffers[ch];
+ //move tail of previous
+ std::copy(pCb->input.begin() + processFrames,
+ pCb->input.end(),
+ pCb->input.begin());
+
+ //read new available data
+ for (unsigned int k = 0; k < processFrames; k++) {
+ pCb->input[mOverlapSize + k] = pCb->cBInput.read();
+ }
+ //first stages: fft, preEq, mbc, postEq and start of Limiter
+ processedSamples += processFirstStages(*pCb);
+ }
+
+ //**compute linked limiters and update levels if needed
+ processLinkedLimiters(channelBuffers);
+
+ //final pass.
+ for (int ch = 0; ch < channelCount; ch++) {
+ ChannelBuffer * pCb = &channelBuffers[ch];
+
+ //linked limiter and ifft
+ processLastStages(*pCb);
+
+ //mix tail (and capture new tail
+ for (unsigned int k = 0; k < mOverlapSize; k++) {
+ pCb->output[k] += pCb->outTail[k];
+ pCb->outTail[k] = pCb->output[processFrames + k]; //new tail
+ }
+
+ //output data
+ for (unsigned int k = 0; k < processFrames; k++) {
+ pCb->cBOutput.write(pCb->output[k]);
+ }
+ }
+ available -= processFrames;
+ }
return processedSamples;
}
-
-size_t DPFrequency::processOneVector(FloatVec & output, FloatVec & input,
- ChannelBuffer &cb) {
+size_t DPFrequency::processFirstStages(ChannelBuffer &cb) {
//##apply window
Eigen::Map<Eigen::VectorXf> eWindow(&mVWindow[0], mVWindow.size());
- Eigen::Map<Eigen::VectorXf> eInput(&input[0], input.size());
+ Eigen::Map<Eigen::VectorXf> eInput(&cb.input[0], cb.input.size());
Eigen::VectorXf eWin = eInput.cwiseProduct(eWindow); //apply window
- //##fft //TODO: refactor frequency transformations away from other stages.
- mFftServer.fwd(mComplexTemp, eWin);
+ //##fft
+ //Note: we are using eigen with the default scaling, which ensures that
+ // IFFT( FFT(x) ) = x.
+ // TODO: optimize by using the noscale option, and compensate with dB scale offsets
+ mFftServer.fwd(cb.complexTemp, eWin);
- size_t cSize = mComplexTemp.size();
+ size_t cSize = cb.complexTemp.size();
size_t maxBin = std::min(cSize/2, mHalfFFTSize);
//== EqPre (always runs)
for (size_t k = 0; k < maxBin; k++) {
- mComplexTemp[k] *= cb.mPreEqFactorVector[k];
+ cb.complexTemp[k] *= cb.mPreEqFactorVector[k];
}
//== MBC
@@ -439,62 +510,68 @@
float preGainSquared = preGainFactor * preGainFactor;
for (size_t k = pMbcBandParams->binStart; k <= pMbcBandParams->binStop; k++) {
- float fReal = mComplexTemp[k].real();
- float fImag = mComplexTemp[k].imag();
- float fSquare = (fReal * fReal + fImag * fImag) * preGainSquared;
-
- fEnergySum += fSquare;
+ fEnergySum += std::norm(cb.complexTemp[k]) * preGainSquared; //mag squared
}
- fEnergySum = sqrt(fEnergySum /2.0);
+ //Eigen FFT is full spectrum, even if the source was real data.
+ // Each half spectrum has half the energy. This is taken into account with the * 2
+ // factor in the energy computations.
+ // energy = sqrt(sum_components_squared) number_points
+ // in here, the fEnergySum is duplicated to account for the second half spectrum,
+ // and the windowRms is used to normalize by the expected energy reduction
+ // caused by the window used (expected for steady state signals)
+ fEnergySum = sqrt(fEnergySum * 2) / (mBlockSize * mWindowRms);
+
+ // updates computed per frame advance.
float fTheta = 0.0;
- float fFAtt = pMbcBandParams->attackTimeMs;
- float fFRel = pMbcBandParams->releaseTimeMs;
-
- float fUpdatesPerSecond = 10; //TODO: compute from framerate
-
+ float fFAttSec = pMbcBandParams->attackTimeMs / 1000; //in seconds
+ float fFRelSec = pMbcBandParams->releaseTimeMs / 1000; //in seconds
if (fEnergySum > pMbcBandParams->previousEnvelope) {
- fTheta = exp(-1.0 / (fFAtt * fUpdatesPerSecond));
+ fTheta = exp(-1.0 / (fFAttSec * mBlocksPerSecond));
} else {
- fTheta = exp(-1.0 / (fFRel * fUpdatesPerSecond));
+ fTheta = exp(-1.0 / (fFRelSec * mBlocksPerSecond));
}
float fEnv = (1.0 - fTheta) * fEnergySum + fTheta * pMbcBandParams->previousEnvelope;
-
//preserve for next iteration
pMbcBandParams->previousEnvelope = fEnv;
- float fThreshold = dBtoLinear(pMbcBandParams->thresholdDb);
- float fNoiseGateThreshold = dBtoLinear(pMbcBandParams->noiseGateThresholdDb);
-
- float fNewFactor = 1.0;
-
- if (fEnv > fThreshold) {
- float fDbAbove = linearToDb(fThreshold / fEnv);
- float fDbTarget = fDbAbove / pMbcBandParams->ratio;
- float fDbChange = fDbAbove - fDbTarget;
- fNewFactor = dBtoLinear(fDbChange);
- } else if (fEnv < fNoiseGateThreshold) {
- if (fEnv < MIN_ENVELOPE) {
- fEnv = MIN_ENVELOPE;
- }
- float fDbBelow = linearToDb(fNoiseGateThreshold / fEnv);
- float fDbTarget = fDbBelow / pMbcBandParams->expanderRatio;
- float fDbChange = fDbBelow - fDbTarget;
- fNewFactor = dBtoLinear(fDbChange);
+ if (fEnv < MIN_ENVELOPE) {
+ fEnv = MIN_ENVELOPE;
}
+ const float envDb = linearToDb(fEnv);
+ float newLevelDb = envDb;
+ //using shorter variables for code clarity
+ const float thresholdDb = pMbcBandParams->thresholdDb;
+ const float ratio = pMbcBandParams->ratio;
+ const float kneeWidthDbHalf = pMbcBandParams->kneeWidthDb / 2;
+ const float noiseGateThresholdDb = pMbcBandParams->noiseGateThresholdDb;
+ const float expanderRatio = pMbcBandParams->expanderRatio;
+
+ //find segment
+ if (envDb > thresholdDb + kneeWidthDbHalf) {
+ //compression segment
+ newLevelDb = envDb + ((1 / ratio) - 1) * (envDb - thresholdDb);
+ } else if (envDb > thresholdDb - kneeWidthDbHalf) {
+ //knee-compression segment
+ float temp = (envDb - thresholdDb + kneeWidthDbHalf);
+ newLevelDb = envDb + ((1 / ratio) - 1) *
+ temp * temp / (kneeWidthDbHalf * 4);
+ } else if (envDb < noiseGateThresholdDb) {
+ //expander segment
+ newLevelDb = noiseGateThresholdDb -
+ expanderRatio * (noiseGateThresholdDb - envDb);
+ }
+
+ float newFactor = dBtoLinear(newLevelDb - envDb);
//apply post gain.
- fNewFactor *= dBtoLinear(pMbcBandParams->gainPostDb);
-
- if (fNewFactor < 0) {
- fNewFactor = 0;
- }
+ newFactor *= dBtoLinear(pMbcBandParams->gainPostDb);
//apply to this band
for (size_t k = pMbcBandParams->binStart; k <= pMbcBandParams->binStop; k++) {
- mComplexTemp[k] *= fNewFactor;
+ cb.complexTemp[k] *= newFactor;
}
} //end per band process
@@ -504,14 +581,94 @@
//== EqPost
if (cb.mPostEqInUse && cb.mPostEqEnabled) {
for (size_t k = 0; k < maxBin; k++) {
- mComplexTemp[k] *= cb.mPostEqFactorVector[k];
+ cb.complexTemp[k] *= cb.mPostEqFactorVector[k];
+ }
+ }
+
+ //== Limiter. First Pass
+ if (cb.mLimiterInUse && cb.mLimiterEnabled) {
+ float fEnergySum = 0;
+ for (size_t k = 0; k < maxBin; k++) {
+ fEnergySum += std::norm(cb.complexTemp[k]);
+ }
+
+ //see explanation above for energy computation logic
+ fEnergySum = sqrt(fEnergySum * 2) / (mBlockSize * mWindowRms);
+ float fTheta = 0.0;
+ float fFAttSec = cb.mLimiterParams.attackTimeMs / 1000; //in seconds
+ float fFRelSec = cb.mLimiterParams.releaseTimeMs / 1000; //in seconds
+
+ if (fEnergySum > cb.mLimiterParams.previousEnvelope) {
+ fTheta = exp(-1.0 / (fFAttSec * mBlocksPerSecond));
+ } else {
+ fTheta = exp(-1.0 / (fFRelSec * mBlocksPerSecond));
+ }
+
+ float fEnv = (1.0 - fTheta) * fEnergySum + fTheta * cb.mLimiterParams.previousEnvelope;
+ //preserve for next iteration
+ cb.mLimiterParams.previousEnvelope = fEnv;
+
+ const float envDb = linearToDb(fEnv);
+ float newFactorDb = 0;
+ //using shorter variables for code clarity
+ const float thresholdDb = cb.mLimiterParams.thresholdDb;
+ const float ratio = cb.mLimiterParams.ratio;
+
+ if (envDb > thresholdDb) {
+ //limiter segment
+ newFactorDb = ((1 / ratio) - 1) * (envDb - thresholdDb);
+ }
+
+ float newFactor = dBtoLinear(newFactorDb);
+
+ cb.mLimiterParams.newFactor = newFactor;
+
+ } //end Limiter
+ return mBlockSize;
+}
+
+void DPFrequency::processLinkedLimiters(CBufferVector &channelBuffers) {
+
+ const int channelCount = channelBuffers.size();
+ for (auto &groupPair : mLinkedLimiters.mGroupsMap) {
+ float minFactor = 1.0;
+ //estimate minfactor for all linked
+ for(int index : groupPair.second) {
+ if (index >= 0 && index < channelCount) {
+ minFactor = std::min(channelBuffers[index].mLimiterParams.newFactor, minFactor);
+ }
+ }
+ //apply minFactor
+ for(int index : groupPair.second) {
+ if (index >= 0 && index < channelCount) {
+ channelBuffers[index].mLimiterParams.linkFactor = minFactor;
+ }
+ }
+ }
+}
+
+size_t DPFrequency::processLastStages(ChannelBuffer &cb) {
+
+ float outputGainFactor = dBtoLinear(cb.outputGainDb);
+ //== Limiter. last Pass
+ if (cb.mLimiterInUse && cb.mLimiterEnabled) {
+ //compute factor, with post-gain
+ float factor = cb.mLimiterParams.linkFactor * dBtoLinear(cb.mLimiterParams.postGainDb);
+ outputGainFactor *= factor;
+ }
+
+ //apply to all if != 1.0
+ if (!compareEquality(outputGainFactor, 1.0f)) {
+ size_t cSize = cb.complexTemp.size();
+ size_t maxBin = std::min(cSize/2, mHalfFFTSize);
+ for (size_t k = 0; k < maxBin; k++) {
+ cb.complexTemp[k] *= outputGainFactor;
}
}
//##ifft directly to output.
- Eigen::Map<Eigen::VectorXf> eOutput(&output[0], output.size());
- mFftServer.inv(eOutput, mComplexTemp);
-
+ Eigen::Map<Eigen::VectorXf> eOutput(&cb.output[0], cb.output.size());
+ mFftServer.inv(eOutput, cb.complexTemp);
return mBlockSize;
}
diff --git a/media/libeffects/dynamicsproc/dsp/DPFrequency.h b/media/libeffects/dynamicsproc/dsp/DPFrequency.h
index 9919142..be8771d 100644
--- a/media/libeffects/dynamicsproc/dsp/DPFrequency.h
+++ b/media/libeffects/dynamicsproc/dsp/DPFrequency.h
@@ -39,8 +39,11 @@
FloatVec output; // time domain temp vector for output
FloatVec outTail; // time domain temp vector for output tail (for overlap-add method)
+ Eigen::VectorXcf complexTemp; // complex temp vector for frequency domain operations
+
//Current parameters
float inputGainDb;
+ float outputGainDb;
struct BandParams {
bool enabled;
float freqCutoffHz;
@@ -64,6 +67,19 @@
//Historic values
float previousEnvelope;
};
+ struct LimiterParams {
+ int32_t linkGroup;
+ float attackTimeMs;
+ float releaseTimeMs;
+ float ratio;
+ float thresholdDb;
+ float postGainDb;
+
+ //Historic values
+ float previousEnvelope;
+ float newFactor;
+ float linkFactor;
+ };
bool mPreEqInUse;
bool mPreEqEnabled;
@@ -79,6 +95,7 @@
bool mLimiterInUse;
bool mLimiterEnabled;
+ LimiterParams mLimiterParams;
FloatVec mPreEqFactorVector; // temp pre-computed vector to shape spectrum at preEQ stage
FloatVec mPostEqFactorVector; // temp pre-computed vector to shape spectrum at postEQ stage
@@ -91,6 +108,18 @@
};
+using CBufferVector = std::vector<ChannelBuffer>;
+
+using GroupsMap = std::map<int32_t, IntVec>;
+
+class LinkedLimiters {
+public:
+ void reset();
+ void update(int32_t group, int index);
+ void remove(int index);
+ GroupsMap mGroupsMap;
+};
+
class DPFrequency : public DPBase {
public:
virtual size_t processSamples(const float *in, float *out, size_t samples);
@@ -104,16 +133,25 @@
size_t processMono(ChannelBuffer &cb);
size_t processOneVector(FloatVec &output, FloatVec &input, ChannelBuffer &cb);
+ size_t processChannelBuffers(CBufferVector &channelBuffers);
+ size_t processFirstStages(ChannelBuffer &cb);
+ size_t processLastStages(ChannelBuffer &cb);
+ void processLinkedLimiters(CBufferVector &channelBuffers);
+
size_t mBlockSize;
size_t mHalfFFTSize;
size_t mOverlapSize;
size_t mSamplingRate;
- std::vector<ChannelBuffer> mChannelBuffers;
+ float mBlocksPerSecond;
+
+ CBufferVector mChannelBuffers;
+
+ LinkedLimiters mLinkedLimiters;
//dsp
FloatVec mVWindow; //window class.
- Eigen::VectorXcf mComplexTemp;
+ float mWindowRms;
Eigen::FFT<float> mFftServer;
};
diff --git a/media/libeffects/dynamicsproc/dsp/RDsp.h b/media/libeffects/dynamicsproc/dsp/RDsp.h
index 1048442..cfa1305 100644
--- a/media/libeffects/dynamicsproc/dsp/RDsp.h
+++ b/media/libeffects/dynamicsproc/dsp/RDsp.h
@@ -20,10 +20,25 @@
#include <complex>
#include <log/log.h>
#include <vector>
+#include <map>
using FloatVec = std::vector<float>;
+using IntVec = std::vector<int>;
using ComplexVec = std::vector<std::complex<float>>;
// =======
+// Helper Functions
+// =======
+template <class T>
+static T dBtoLinear(T valueDb) {
+ return pow (10, valueDb / 20.0);
+}
+
+template <class T>
+static T linearToDb(T value) {
+ return 20 * log10(value);
+}
+
+// =======
// DSP window creation
// =======
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index cbc3015..23d66bb 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -934,7 +934,11 @@
sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
if (meta == NULL) {
ALOGE("no metadata for track %zu", trackIndex);
- return NULL;
+ format->setInt32("type", MEDIA_TRACK_TYPE_UNKNOWN);
+ format->setString("mime", "application/octet-stream");
+ format->setString("language", "und");
+
+ return format;
}
const char *mime;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
index 0402fca..fb12360 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
@@ -155,7 +155,9 @@
break;
default:
ALOGE("Unknown track type: %d", track.mTrackType);
- return NULL;
+ format->setInt32("type", MEDIA_TRACK_TYPE_UNKNOWN);
+ format->setString("mime", "application/octet-stream");
+ return format;
}
// For CEA-608 CC1, field 0 channel 0
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 2a08f62..69cd82e 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -745,6 +745,7 @@
sp<AMessage> reply = new AMessage(kWhatRenderBuffer, this);
reply->setSize("buffer-ix", index);
reply->setInt32("generation", mBufferGeneration);
+ reply->setSize("size", size);
if (eos) {
ALOGI("[%s] saw output EOS", mIsAudio ? "audio" : "video");
@@ -1127,6 +1128,7 @@
int32_t render;
size_t bufferIx;
int32_t eos;
+ size_t size;
CHECK(msg->findSize("buffer-ix", &bufferIx));
if (!mIsAudio) {
@@ -1146,7 +1148,10 @@
CHECK(msg->findInt64("timestampNs", ×tampNs));
err = mCodec->renderOutputBufferAndRelease(bufferIx, timestampNs);
} else {
- mNumOutputFramesDropped += !mIsAudio;
+ if (!msg->findInt32("eos", &eos) || !eos ||
+ !msg->findSize("size", &size) || size) {
+ mNumOutputFramesDropped += !mIsAudio;
+ }
err = mCodec->releaseOutputBuffer(bufferIx);
}
if (err != OK) {
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 2abea9e..bf5ae2c 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -5322,13 +5322,13 @@
convertCodecColorAspectsToPlatformAspects(aspects, &range, &standard, &transfer);
// if some aspects are unspecified, use dataspace fields
- if (range != 0) {
+ if (range == 0) {
range = (dataSpace & HAL_DATASPACE_RANGE_MASK) >> HAL_DATASPACE_RANGE_SHIFT;
}
- if (standard != 0) {
+ if (standard == 0) {
standard = (dataSpace & HAL_DATASPACE_STANDARD_MASK) >> HAL_DATASPACE_STANDARD_SHIFT;
}
- if (transfer != 0) {
+ if (transfer == 0) {
transfer = (dataSpace & HAL_DATASPACE_TRANSFER_MASK) >> HAL_DATASPACE_TRANSFER_SHIFT;
}
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 06a49d0..8436591 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -854,8 +854,7 @@
//static
sp<CodecBase> MediaCodec::GetCodecBase(const AString &name) {
- static bool ccodecEnabled = property_get_bool("debug.stagefright.ccodec", false);
- if (ccodecEnabled && name.startsWithIgnoreCase("c2.")) {
+ if (name.startsWithIgnoreCase("c2.")) {
return CreateCCodec();
} else if (name.startsWithIgnoreCase("omx.")) {
// at this time only ACodec specifies a mime type.
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 9a33168..8598a49 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -93,9 +93,7 @@
std::vector<MediaCodecListBuilderBase *> GetBuilders() {
std::vector<MediaCodecListBuilderBase *> builders {&sOmxInfoBuilder};
- if (property_get_bool("debug.stagefright.ccodec", false)) {
- builders.push_back(GetCodec2InfoBuilder());
- }
+ builders.push_back(GetCodec2InfoBuilder());
return builders;
}
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index 43304aa..df66ac6 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -197,6 +197,7 @@
CHECK(mNumItems < kMaxNumItems);
i = mNumItems++;
item = &mItems[i];
+ item->mType = kTypeInt32;
item->setName(name, len);
}
diff --git a/services/audiopolicy/common/managerdefinitions/include/SessionRoute.h b/services/audiopolicy/common/managerdefinitions/include/SessionRoute.h
index fac6cbe..32b4440 100644
--- a/services/audiopolicy/common/managerdefinitions/include/SessionRoute.h
+++ b/services/audiopolicy/common/managerdefinitions/include/SessionRoute.h
@@ -24,6 +24,7 @@
namespace android {
class DeviceDescriptor;
+class DeviceVector;
class SessionRoute : public RefBase
{
@@ -98,7 +99,8 @@
int decRouteActivity(audio_session_t session);
bool getAndClearRouteChanged(audio_session_t session); // also clears the changed flag
void log(const char* caption);
-
+ audio_devices_t getActiveDeviceForStream(audio_stream_type_t streamType,
+ const DeviceVector& availableDevices);
// Specify an Output(Sink) route by passing SessionRoute::SOURCE_TYPE_NA in the
// source argument.
// Specify an Input(Source) rout by passing SessionRoute::AUDIO_STREAM_DEFAULT
diff --git a/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp b/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp
index 8edd4d1..d34214b 100644
--- a/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp
@@ -82,7 +82,7 @@
void SessionRouteMap::log(const char* caption)
{
ALOGI("%s ----", caption);
- for(size_t index = 0; index < size(); index++) {
+ for (size_t index = 0; index < size(); index++) {
valueAt(index)->log(" ");
}
}
@@ -119,4 +119,22 @@
}
}
+audio_devices_t SessionRouteMap::getActiveDeviceForStream(audio_stream_type_t streamType,
+ const DeviceVector& availableDevices)
+{
+ audio_devices_t device = AUDIO_DEVICE_NONE;
+
+ for (size_t index = 0; index < size(); index++) {
+ sp<SessionRoute> route = valueAt(index);
+ if (streamType == route->mStreamType && route->isActiveOrChanged()
+ && route->mDeviceDescriptor != 0) {
+ device = route->mDeviceDescriptor->type();
+ if (!availableDevices.getDevicesFromType(device).isEmpty()) {
+ break;
+ }
+ }
+ }
+ return device;
+}
+
} // namespace android
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 23c020d..3e13e50 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -453,6 +453,12 @@
}
// Use both Bluetooth SCO and phone default output when ringing in normal mode
if (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION] == AUDIO_POLICY_FORCE_BT_SCO) {
+ if ((strategy == STRATEGY_SONIFICATION) &&
+ (device & AUDIO_DEVICE_OUT_SPEAKER) &&
+ (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
+ device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+ device &= ~AUDIO_DEVICE_OUT_SPEAKER;
+ }
if (device2 != AUDIO_DEVICE_NONE) {
device |= device2;
break;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 1e5f9ae..3775551 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1157,7 +1157,9 @@
}
} else if (mOutputRoutes.getAndClearRouteChanged(session)) {
newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/);
- checkStrategyRoute(getStrategy(stream), output);
+ if (newDevice != outputDesc->device()) {
+ checkStrategyRoute(getStrategy(stream), output);
+ }
} else {
newDevice = AUDIO_DEVICE_NONE;
}
@@ -1408,6 +1410,7 @@
(newDevice != desc->device())) {
audio_devices_t newDevice2 = getNewOutputDevice(desc, false /*fromCache*/);
bool force = desc->device() != newDevice2;
+
setOutputDevice(desc,
newDevice2,
force,
@@ -4836,6 +4839,20 @@
}
}
+ // Check if an explicit routing request exists for an active stream on this output and
+ // use it in priority before any other rule
+ for (int stream = 0; stream < AUDIO_STREAM_FOR_POLICY_CNT; stream++) {
+ if (outputDesc->isStreamActive((audio_stream_type_t)stream)) {
+ audio_devices_t forcedDevice =
+ mOutputRoutes.getActiveDeviceForStream(
+ (audio_stream_type_t)stream, mAvailableOutputDevices);
+
+ if (forcedDevice != AUDIO_DEVICE_NONE) {
+ return forcedDevice;
+ }
+ }
+ }
+
// check the following by order of priority to request a routing change if necessary:
// 1: the strategy enforced audible is active and enforced on the output:
// use device for strategy enforced audible
@@ -5043,19 +5060,16 @@
audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy,
bool fromCache)
{
- // Routing
- // see if we have an explicit route
- // scan the whole RouteMap, for each entry, convert the stream type to a strategy
- // (getStrategy(stream)).
- // if the strategy from the stream type in the RouteMap is the same as the argument above,
- // and activity count is non-zero and the device in the route descriptor is available
- // then select this device.
- for (size_t routeIndex = 0; routeIndex < mOutputRoutes.size(); routeIndex++) {
- sp<SessionRoute> route = mOutputRoutes.valueAt(routeIndex);
- routing_strategy routeStrategy = getStrategy(route->mStreamType);
- if ((routeStrategy == strategy) && route->isActiveOrChanged() &&
- (mAvailableOutputDevices.indexOf(route->mDeviceDescriptor) >= 0)) {
- return route->mDeviceDescriptor->type();
+ // Check if an explicit routing request exists for a stream type corresponding to the
+ // specified strategy and use it in priority over default routing rules.
+ for (int stream = 0; stream < AUDIO_STREAM_FOR_POLICY_CNT; stream++) {
+ if (getStrategy((audio_stream_type_t)stream) == strategy) {
+ audio_devices_t forcedDevice =
+ mOutputRoutes.getActiveDeviceForStream(
+ (audio_stream_type_t)stream, mAvailableOutputDevices);
+ if (forcedDevice != AUDIO_DEVICE_NONE) {
+ return forcedDevice;
+ }
}
}
@@ -5625,7 +5639,10 @@
}
float volumeDb = computeVolume(stream, index, device);
- if (outputDesc->isFixedVolume(device)) {
+ if (outputDesc->isFixedVolume(device) ||
+ // Force VoIP volume to max for bluetooth SCO
+ ((stream == AUDIO_STREAM_VOICE_CALL || stream == AUDIO_STREAM_BLUETOOTH_SCO) &&
+ (device & AUDIO_DEVICE_OUT_ALL_SCO) != 0)) {
volumeDb = 0.0f;
}
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index f4d5a18..59ac636 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -212,7 +212,11 @@
SP_LOGV("%s: Consumer wants %d buffers, Producer wants %zu", __FUNCTION__,
maxConsumerBuffers, mMaxHalBuffers);
- size_t totalBufferCount = maxConsumerBuffers + mMaxHalBuffers;
+ // The output slot count requirement can change depending on the current amount
+ // of outputs and incoming buffer consumption rate. To avoid any issues with
+ // insufficient slots, set their count to the maximum supported. The output
+ // surface buffer allocation is disabled so no real buffers will get allocated.
+ size_t totalBufferCount = BufferQueue::NUM_BUFFER_SLOTS;
res = native_window_set_buffer_count(outputQueue.get(),
totalBufferCount);
if (res != OK) {