Add setMasterMono and getMasterMono
Bug: 15283594
Bug: 22700363
Change-Id: I32dc1fcecf285967a61bd508af3bb299595db57d
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 45c68b5..5991eab 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -37,6 +37,7 @@
#include <cpustats/ThreadCpuUsage.h>
#endif
#endif
+#include <audio_utils/conversion.h>
#include <audio_utils/format.h>
#include "AudioMixer.h"
#include "FastMixer.h"
@@ -66,7 +67,8 @@
mFastTracksGen(0),
mTotalNativeFramesWritten(0),
// timestamp
- mNativeFramesWrittenButNotPresented(0) // the = 0 is to silence the compiler
+ mNativeFramesWrittenButNotPresented(0), // the = 0 is to silence the compiler
+ mMasterMono(false)
{
// FIXME pass sInitial as parameter to base class constructor, and make it static local
mPrevious = &sInitial;
@@ -419,6 +421,10 @@
memset(mMixerBuffer, 0, mMixerBufferSize);
mMixerBufferState = ZEROED;
}
+
+ if (mMasterMono.load()) { // memory_order_seq_cst
+ mono_blend(mMixerBuffer, mMixerBufferFormat, Format_channelCount(mFormat), frameCount);
+ }
// prepare the buffer used to write to sink
void *buffer = mSinkBuffer != NULL ? mSinkBuffer : mMixerBuffer;
if (mFormat.mFormat != mMixerBufferFormat) { // sink format not the same as mixer format
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index 06a68fb..e38878e 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_AUDIO_FAST_MIXER_H
#define ANDROID_AUDIO_FAST_MIXER_H
+#include <atomic>
#include "FastThread.h"
#include "StateQueue.h"
#include "FastMixerState.h"
@@ -36,6 +37,8 @@
FastMixerStateQueue* sq();
+ virtual void setMasterMono(bool mono) { mMasterMono.store(mono); /* memory_order_seq_cst */ }
+
private:
FastMixerStateQueue mSQ;
@@ -82,6 +85,8 @@
AudioTimestamp mTimestamp;
uint32_t mNativeFramesWrittenButNotPresented;
+ // accessed without lock between multiple threads.
+ std::atomic_bool mMasterMono;
}; // class FastMixer
} // namespace android
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 7c9b81e..fb89699 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -36,6 +36,7 @@
#include <hardware/audio.h>
#include <audio_effects/effect_ns.h>
#include <audio_effects/effect_aec.h>
+#include <audio_utils/conversion.h>
#include <audio_utils/primitives.h>
#include <audio_utils/format.h>
#include <audio_utils/minifloat.h>
@@ -669,7 +670,19 @@
// sendSetParameterConfigEvent_l() must be called with ThreadBase::mLock held
status_t AudioFlinger::ThreadBase::sendSetParameterConfigEvent_l(const String8& keyValuePair)
{
- sp<ConfigEvent> configEvent = (ConfigEvent *)new SetParameterConfigEvent(keyValuePair);
+ sp<ConfigEvent> configEvent;
+ AudioParameter param(keyValuePair);
+ int value;
+ if (param.getInt(String8(AUDIO_PARAMETER_MONO_OUTPUT), value) == NO_ERROR) {
+ setMasterMono_l(value != 0);
+ if (param.size() == 1) {
+ return NO_ERROR; // should be a solo parameter - we don't pass down
+ }
+ param.remove(String8(AUDIO_PARAMETER_MONO_OUTPUT));
+ configEvent = new SetParameterConfigEvent(param.toString());
+ } else {
+ configEvent = new SetParameterConfigEvent(keyValuePair);
+ }
return sendConfigEvent_l(configEvent);
}
@@ -2903,6 +2916,13 @@
void *buffer = mEffectBufferValid ? mEffectBuffer : mSinkBuffer;
audio_format_t format = mEffectBufferValid ? mEffectBufferFormat : mFormat;
+ // mono blend occurs for mixer threads only (not direct or offloaded)
+ // and is handled here if we're going directly to the sink.
+ if (requireMonoBlend() && !mEffectBufferValid) {
+ mono_blend(
+ mMixerBuffer, mMixerBufferFormat, mChannelCount, mNormalFrameCount);
+ }
+
memcpy_by_audio_format(buffer, format, mMixerBuffer, mMixerBufferFormat,
mNormalFrameCount * mChannelCount);
}
@@ -2938,6 +2958,11 @@
// TODO use mSleepTimeUs == 0 as an additional condition.
if (mEffectBufferValid) {
//ALOGV("writing effect buffer to sink buffer format %#x", mFormat);
+
+ if (requireMonoBlend()) {
+ mono_blend(mEffectBuffer, mEffectBufferFormat, mChannelCount, mNormalFrameCount);
+ }
+
memcpy_by_audio_format(mSinkBuffer, mFormat, mEffectBuffer, mEffectBufferFormat,
mNormalFrameCount * mChannelCount);
}
@@ -3280,7 +3305,8 @@
: PlaybackThread(audioFlinger, output, id, device, type, systemReady),
// mAudioMixer below
// mFastMixer below
- mFastMixerFutex(0)
+ mFastMixerFutex(0),
+ mMasterMono(false)
// mOutputSink below
// mPipeSink below
// mNormalSink below
@@ -4404,6 +4430,7 @@
PlaybackThread::dumpInternals(fd, args);
dprintf(fd, " Thread throttle time (msecs): %u\n", mThreadThrottleTimeMs);
dprintf(fd, " AudioMixer tracks: 0x%08x\n", mAudioMixer->trackNames());
+ dprintf(fd, " Master mono: %s\n", mMasterMono ? "on" : "off");
// Make a non-atomic copy of fast mixer dump state so it won't change underneath us
// while we are dumping it. It may be inconsistent, but it won't mutate!
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 114d43c..8eed50d 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -400,6 +400,8 @@
String16 getWakeLockTag();
virtual void preExit() { }
+ virtual void setMasterMono_l(bool mono __unused) { }
+ virtual bool requireMonoBlend() { return false; }
friend class AudioFlinger; // for mEffectChains
@@ -909,6 +911,7 @@
// mFastMixer->sq() // for mutating and pushing state
int32_t mFastMixerFutex; // for cold idle
+ std::atomic_bool mMasterMono;
public:
virtual bool hasFastMixer() const { return mFastMixer != 0; }
virtual FastTrackUnderruns getFastTrackUnderruns(size_t fastIndex) const {
@@ -916,6 +919,15 @@
return mFastMixerDumpState.mTracks[fastIndex].mUnderruns;
}
+protected:
+ virtual void setMasterMono_l(bool mono) {
+ mMasterMono.store(mono);
+ if (mFastMixer != nullptr) { /* hasFastMixer() */
+ mFastMixer->setMasterMono(mMasterMono);
+ }
+ }
+ // the FastMixer performs mono blend if it exists.
+ virtual bool requireMonoBlend() { return mMasterMono.load() && !hasFastMixer(); }
};
class DirectOutputThread : public PlaybackThread {