Add setMasterMono and getMasterMono
Bug: 15283594
Bug: 22700363
Change-Id: I32dc1fcecf285967a61bd508af3bb299595db57d
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 26a0bb2..9df131a 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -319,6 +319,8 @@
audio_io_handle_t *handle);
static status_t stopAudioSource(audio_io_handle_t handle);
+ static status_t setMasterMono(bool mono);
+ static status_t getMasterMono(bool *mono);
// ----------------------------------------------------------------------------
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index 6b93f6f..ceca71a 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -165,6 +165,9 @@
const audio_attributes_t *attributes,
audio_io_handle_t *handle) = 0;
virtual status_t stopAudioSource(audio_io_handle_t handle) = 0;
+
+ virtual status_t setMasterMono(bool mono) = 0;
+ virtual status_t getMasterMono(bool *mono) = 0;
};
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 9d645f0..37e590c 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -1159,6 +1159,20 @@
return aps->stopAudioSource(handle);
}
+status_t AudioSystem::setMasterMono(bool mono)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->setMasterMono(mono);
+}
+
+status_t AudioSystem::getMasterMono(bool *mono)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->getMasterMono(mono);
+}
+
// ---------------------------------------------------------------------------
int AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index 76b5924..c95d4c4 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -74,6 +74,8 @@
START_AUDIO_SOURCE,
STOP_AUDIO_SOURCE,
SET_AUDIO_PORT_CALLBACK_ENABLED,
+ SET_MASTER_MONO,
+ GET_MASTER_MONO,
};
#define MAX_ITEMS_PER_LIST 1024
@@ -767,6 +769,37 @@
status = (status_t)reply.readInt32();
return status;
}
+
+ virtual status_t setMasterMono(bool mono)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(static_cast<int32_t>(mono));
+ status_t status = remote()->transact(SET_MASTER_MONO, data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return static_cast<status_t>(reply.readInt32());
+ }
+
+ virtual status_t getMasterMono(bool *mono)
+ {
+ if (mono == nullptr) {
+ return BAD_VALUE;
+ }
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+
+ status_t status = remote()->transact(GET_MASTER_MONO, data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = static_cast<status_t>(reply.readInt32());
+ if (status == NO_ERROR) {
+ *mono = static_cast<bool>(reply.readInt32());
+ }
+ return status;
+ }
};
IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -1311,6 +1344,25 @@
return NO_ERROR;
} break;
+ case SET_MASTER_MONO: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ bool mono = static_cast<bool>(data.readInt32());
+ status_t status = setMasterMono(mono);
+ reply->writeInt32(status);
+ return NO_ERROR;
+ } break;
+
+ case GET_MASTER_MONO: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ bool mono;
+ status_t status = getMasterMono(&mono);
+ reply->writeInt32(status);
+ if (status == NO_ERROR) {
+ reply->writeInt32(static_cast<int32_t>(mono));
+ }
+ return NO_ERROR;
+ } break;
+
default:
return BBinder::onTransact(code, data, reply, flags);
}
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 {
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 7cf44dc..c4dee5a 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -228,6 +228,9 @@
audio_io_handle_t *handle,
uid_t uid) = 0;
virtual status_t stopAudioSource(audio_io_handle_t handle) = 0;
+
+ virtual status_t setMasterMono(bool mono) = 0;
+ virtual status_t getMasterMono(bool *mono) = 0;
};
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 11dabae..3040833 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -842,15 +842,15 @@
goto non_direct_output;
}
- // Do not allow offloading if one non offloadable effect is enabled. This prevents from
- // creating an offloaded track and tearing it down immediately after start when audioflinger
- // detects there is an active non offloadable effect.
+ // Do not allow offloading if one non offloadable effect is enabled or MasterMono is enabled.
+ // This prevents creating an offloaded track and tearing it down immediately after start
+ // when audioflinger detects there is an active non offloadable effect.
// FIXME: We should check the audio session here but we do not have it in this context.
// This may prevent offloading in rare situations where effects are left active by apps
// in the background.
if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) ||
- !mEffects.isNonOffloadableEffectEnabled()) {
+ !(mEffects.isNonOffloadableEffectEnabled() || mMasterMono)) {
profile = getProfileForDirectOutput(device,
samplingRate,
format,
@@ -2088,6 +2088,8 @@
result.append(buffer);
snprintf(buffer, SIZE, " TTS output %s\n", mTtsOutputAvailable ? "available" : "not available");
result.append(buffer);
+ snprintf(buffer, SIZE, " Master mono: %s\n", mMasterMono ? "on" : "off");
+ result.append(buffer);
write(fd, result.string(), result.size());
@@ -2115,6 +2117,10 @@
offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us,
offloadInfo.has_video);
+ if (mMasterMono) {
+ return false; // no offloading if mono is set.
+ }
+
// Check if offload has been disabled
char propValue[PROPERTY_VALUE_MAX];
if (property_get("audio.offload.disable", propValue, "0")) {
@@ -2878,6 +2884,44 @@
return status;
}
+status_t AudioPolicyManager::setMasterMono(bool mono)
+{
+ if (mMasterMono == mono) {
+ return NO_ERROR;
+ }
+ mMasterMono = mono;
+ // if enabling mono we close all offloaded devices, which will invalidate the
+ // corresponding AudioTrack. The AudioTrack client/MediaPlayer is responsible
+ // for recreating the new AudioTrack as non-offloaded PCM.
+ //
+ // If disabling mono, we leave all tracks as is: we don't know which clients
+ // and tracks are able to be recreated as offloaded. The next "song" should
+ // play back offloaded.
+ if (mMasterMono) {
+ Vector<audio_io_handle_t> offloaded;
+ for (size_t i = 0; i < mOutputs.size(); ++i) {
+ sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
+ if (desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+ offloaded.push(desc->mIoHandle);
+ }
+ }
+ for (size_t i = 0; i < offloaded.size(); ++i) {
+ closeOutput(offloaded[i]);
+ }
+ }
+ // update master mono for all remaining outputs
+ for (size_t i = 0; i < mOutputs.size(); ++i) {
+ updateMono(mOutputs.keyAt(i));
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::getMasterMono(bool *mono)
+{
+ *mono = mMasterMono;
+ return NO_ERROR;
+}
+
status_t AudioPolicyManager::disconnectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc)
{
ALOGV("%s handle %d", __FUNCTION__, sourceDesc->getHandle());
@@ -2944,7 +2988,8 @@
mBeaconMuteRefCount(0),
mBeaconPlayingRefCount(0),
mBeaconMuted(false),
- mTtsOutputAvailable(false)
+ mTtsOutputAvailable(false),
+ mMasterMono(false)
{
audio_policy::EngineInstance *engineInstance = audio_policy::EngineInstance::getInstance();
if (!engineInstance) {
@@ -3368,6 +3413,7 @@
{
outputDesc->setIoHandle(output);
mOutputs.add(output, outputDesc);
+ updateMono(output); // update mono status when adding to output list
nextAudioPortGeneration();
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 59163ca..37faac2 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -24,6 +24,7 @@
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/SortedVector.h>
+#include <media/AudioParameter.h>
#include <media/AudioPolicy.h>
#include "AudioPolicyInterface.h"
@@ -231,6 +232,9 @@
uid_t uid);
virtual status_t stopAudioSource(audio_io_handle_t handle);
+ virtual status_t setMasterMono(bool mono);
+ virtual status_t getMasterMono(bool *mono);
+
// Audio policy configuration file parsing (audio_policy.conf)
// TODO candidates to be moved to ConfigParsingUtils
void defaultAudioPolicyConfig(void);
@@ -565,6 +569,7 @@
bool mBeaconMuted; // has STREAM_TTS been muted
bool mTtsOutputAvailable; // true if a dedicated output for TTS stream is available
+ bool mMasterMono; // true if we wish to force all outputs to mono
AudioPolicyMixCollection mPolicyMixes; // list of registered mixes
#ifdef AUDIO_POLICY_TEST
@@ -644,6 +649,11 @@
audio_policy_dev_state_t state,
const char *device_address,
const char *device_name);
+ void updateMono(audio_io_handle_t output) {
+ AudioParameter param;
+ param.addInt(String8(AUDIO_PARAMETER_MONO_OUTPUT), (int)mMasterMono);
+ mpClientInterface->setParameters(output, param.toString());
+ }
};
};
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 8c976aa..c7486a5 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -560,7 +560,7 @@
ALOGV("mAudioPolicyManager == NULL");
return false;
}
-
+ Mutex::Autolock _l(mLock);
return mAudioPolicyManager->isOffloadSupported(info);
}
@@ -700,4 +700,25 @@
return mAudioPolicyManager->stopAudioSource(handle);
}
+status_t AudioPolicyService::setMasterMono(bool mono)
+{
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+ Mutex::Autolock _l(mLock);
+ return mAudioPolicyManager->setMasterMono(mono);
+}
+
+status_t AudioPolicyService::getMasterMono(bool *mono)
+{
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ Mutex::Autolock _l(mLock);
+ return mAudioPolicyManager->getMasterMono(mono);
+}
+
}; // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
index 13af3ef..08b2a3b 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
@@ -619,4 +619,14 @@
return INVALID_OPERATION;
}
+status_t AudioPolicyService::setMasterMono(bool mono)
+{
+ return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::getMasterMono(bool *mono)
+{
+ return INVALID_OPERATION;
+}
+
}; // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index a0d5aa2..d1ac5d8 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -202,6 +202,9 @@
audio_io_handle_t *handle);
virtual status_t stopAudioSource(audio_io_handle_t handle);
+ virtual status_t setMasterMono(bool mono);
+ virtual status_t getMasterMono(bool *mono);
+
status_t doStopOutput(audio_io_handle_t output,
audio_stream_type_t stream,
audio_session_t session);