Add master audio balance

Test: Change Balance through Settings, play audio
Bug: 28390736
Co-author: Ed Savage-Jones <edward.savage-jones@sony.com>
Change-Id: I0169b436ccbaa5628584d9f4954dd7c76d021aae
gugelfrei
Richard Folke Tullberg 8 years ago committed by Andy Hung
parent 48f59ed61b
commit 3fae037db3

@ -1281,6 +1281,20 @@ status_t AudioSystem::getMasterMono(bool *mono)
return aps->getMasterMono(mono);
}
status_t AudioSystem::setMasterBalance(float balance)
{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
return af->setMasterBalance(balance);
}
status_t AudioSystem::getMasterBalance(float *balance)
{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
return af->getMasterBalance(balance);
}
float AudioSystem::getStreamVolumeDB(audio_stream_type_t stream, int index, audio_devices_t device)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();

@ -87,6 +87,8 @@ enum {
SYSTEM_READY,
FRAME_COUNT_HAL,
GET_MICROPHONES,
SET_MASTER_BALANCE,
GET_MASTER_BALANCE,
};
#define MAX_ITEMS_PER_LIST 1024
@ -242,6 +244,34 @@ public:
return reply.readInt32();
}
status_t setMasterBalance(float balance) override
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeFloat(balance);
status_t status = remote()->transact(SET_MASTER_BALANCE, data, &reply);
if (status != NO_ERROR) {
return status;
}
return reply.readInt32();
}
status_t getMasterBalance(float *balance) const override
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
status_t status = remote()->transact(GET_MASTER_BALANCE, data, &reply);
if (status != NO_ERROR) {
return status;
}
status = (status_t)reply.readInt32();
if (status != NO_ERROR) {
return status;
}
*balance = reply.readFloat();
return NO_ERROR;
}
virtual status_t setStreamVolume(audio_stream_type_t stream, float value,
audio_io_handle_t output)
{
@ -1050,6 +1080,21 @@ status_t BnAudioFlinger::onTransact(
reply->writeInt32( masterMute() );
return NO_ERROR;
} break;
case SET_MASTER_BALANCE: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
reply->writeInt32( setMasterBalance(data.readFloat()) );
return NO_ERROR;
} break;
case GET_MASTER_BALANCE: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
float f;
const status_t status = getMasterBalance(&f);
reply->writeInt32((int32_t)status);
if (status == NO_ERROR) {
(void)reply->writeFloat(f);
}
return NO_ERROR;
} break;
case SET_STREAM_VOLUME: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
int stream = data.readInt32();

@ -339,6 +339,9 @@ public:
static status_t setMasterMono(bool mono);
static status_t getMasterMono(bool *mono);
static status_t setMasterBalance(float balance);
static status_t getMasterBalance(float *balance);
static float getStreamVolumeDB(
audio_stream_type_t stream, int index, audio_devices_t device);

@ -359,6 +359,9 @@ public:
virtual float masterVolume() const = 0;
virtual bool masterMute() const = 0;
virtual status_t setMasterBalance(float balance) = 0;
virtual status_t getMasterBalance(float *balance) const = 0;
/* set/get stream type state. This will probably be used by
* the preference panel, mostly.
*/

@ -897,6 +897,40 @@ status_t AudioFlinger::setMasterVolume(float value)
return NO_ERROR;
}
status_t AudioFlinger::setMasterBalance(float balance)
{
status_t ret = initCheck();
if (ret != NO_ERROR) {
return ret;
}
// check calling permissions
if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
// check range
if (isnan(balance) || fabs(balance) > 1.f) {
return BAD_VALUE;
}
Mutex::Autolock _l(mLock);
// short cut.
if (mMasterBalance == balance) return NO_ERROR;
mMasterBalance = balance;
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
if (mPlaybackThreads.valueAt(i)->isDuplicating()) {
continue;
}
mPlaybackThreads.valueAt(i)->setMasterBalance(balance);
}
return NO_ERROR;
}
status_t AudioFlinger::setMode(audio_mode_t mode)
{
status_t ret = initCheck();
@ -1036,6 +1070,13 @@ float AudioFlinger::masterVolume() const
return masterVolume_l();
}
status_t AudioFlinger::getMasterBalance(float *balance) const
{
Mutex::Autolock _l(mLock);
*balance = getMasterBalance_l();
return NO_ERROR; // if called through binder, may return a transactional error
}
bool AudioFlinger::masterMute() const
{
Mutex::Autolock _l(mLock);
@ -1047,6 +1088,11 @@ float AudioFlinger::masterVolume_l() const
return mMasterVolume;
}
float AudioFlinger::getMasterBalance_l() const
{
return mMasterBalance;
}
bool AudioFlinger::masterMute_l() const
{
return mMasterMute;

@ -137,6 +137,10 @@ public:
virtual float masterVolume() const;
virtual bool masterMute() const;
// Balance value must be within -1.f (left only) to 1.f (right only) inclusive.
status_t setMasterBalance(float balance) override;
status_t getMasterBalance(float *balance) const override;
virtual status_t setStreamVolume(audio_stream_type_t stream, float value,
audio_io_handle_t output);
virtual status_t setStreamMute(audio_stream_type_t stream, bool muted);
@ -776,6 +780,7 @@ using effect_buffer_t = int16_t;
// member variables below are protected by mLock
float mMasterVolume;
bool mMasterMute;
float mMasterBalance = 0.f;
// end of variables protected by mLock
DefaultKeyedVector< audio_io_handle_t, sp<RecordThread> > mRecordThreads;
@ -793,6 +798,7 @@ using effect_buffer_t = int16_t;
Vector<AudioSessionRef*> mAudioSessionRefs;
float masterVolume_l() const;
float getMasterBalance_l() const;
bool masterMute_l() const;
audio_module_handle_t loadHwModule_l(const char *name);

@ -60,7 +60,6 @@ FastMixer::FastMixer(audio_io_handle_t parentIoHandle)
mSinkChannelCount(FCC_2),
mMixerBuffer(NULL),
mMixerBufferSize(0),
mMixerBufferFormat(AUDIO_FORMAT_PCM_16_BIT),
mMixerBufferState(UNDEFINED),
mFormat(Format_Invalid),
mSampleRate(0),
@ -161,6 +160,7 @@ void FastMixer::onStateChange()
mOutputSink = current->mOutputSink;
mOutputSinkGen = current->mOutputSinkGen;
mSinkChannelMask = current->mSinkChannelMask;
mBalance.setChannelMask(mSinkChannelMask);
if (mOutputSink == NULL) {
mFormat = Format_Invalid;
mSampleRate = 0;
@ -191,10 +191,6 @@ void FastMixer::onStateChange()
free(mSinkBuffer);
mSinkBuffer = NULL;
if (frameCount > 0 && mSampleRate > 0) {
// The mixer produces either 16 bit PCM or float output, select
// float output if the HAL supports higher than 16 bit precision.
mMixerBufferFormat = mFormat.mFormat == AUDIO_FORMAT_PCM_16_BIT ?
AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_FLOAT;
// FIXME new may block for unbounded time at internal mutex of the heap
// implementation; it would be better to have normal mixer allocate for us
// to avoid blocking here and to prevent possible priority inversion
@ -471,6 +467,12 @@ void FastMixer::onWork()
mono_blend(mMixerBuffer, mMixerBufferFormat, Format_channelCount(mFormat), frameCount,
true /*limit*/);
}
// Balance must take effect after mono conversion.
// mBalance detects zero balance within the class for speed (not needed here).
mBalance.setBalance(mMasterBalance.load());
mBalance.process((float *)mMixerBuffer, 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

@ -18,6 +18,7 @@
#define ANDROID_AUDIO_FAST_MIXER_H
#include <atomic>
#include <audio_utils/Balance.h>
#include "FastThread.h"
#include "StateQueue.h"
#include "FastMixerState.h"
@ -41,6 +42,8 @@ public:
FastMixerStateQueue* sq();
virtual void setMasterMono(bool mono) { mMasterMono.store(mono); /* memory_order_seq_cst */ }
virtual void setMasterBalance(float balance) { mMasterBalance.store(balance); }
virtual float getMasterBalance() const { return mMasterBalance.load(); }
virtual void setBoottimeOffset(int64_t boottimeOffset) {
mBoottimeOffset.store(boottimeOffset); /* memory_order_seq_cst */
}
@ -74,7 +77,7 @@ private:
audio_channel_mask_t mSinkChannelMask;
void* mMixerBuffer; // mixer output buffer.
size_t mMixerBufferSize;
audio_format_t mMixerBufferFormat; // mixer output format: AUDIO_FORMAT_PCM_(16_BIT|FLOAT).
static constexpr audio_format_t mMixerBufferFormat = AUDIO_FORMAT_PCM_FLOAT;
uint32_t mAudioChannelCount; // audio channel count, excludes haptic channels.
@ -89,8 +92,11 @@ private:
ExtendedTimestamp mTimestamp;
int64_t mNativeFramesWrittenButNotPresented;
audio_utils::Balance mBalance;
// accessed without lock between multiple threads.
std::atomic_bool mMasterMono;
std::atomic<float> mMasterBalance{};
std::atomic_int_fast64_t mBoottimeOffset;
const audio_io_handle_t mThreadIoHandle; // parent thread id for debugging purposes

@ -38,6 +38,7 @@
#include <private/media/AudioTrackShared.h>
#include <private/android_filesystem_config.h>
#include <audio_utils/Balance.h>
#include <audio_utils/channels.h>
#include <audio_utils/mono_blend.h>
#include <audio_utils/primitives.h>
@ -2271,6 +2272,11 @@ void AudioFlinger::PlaybackThread::setMasterVolume(float value)
}
}
void AudioFlinger::PlaybackThread::setMasterBalance(float balance)
{
mMasterBalance.store(balance);
}
void AudioFlinger::PlaybackThread::setMasterMute(bool muted)
{
if (isDuplicating()) {
@ -2523,6 +2529,7 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l()
mChannelMask);
}
mChannelCount = audio_channel_count_from_out_mask(mChannelMask);
mBalance.setChannelMask(mChannelMask);
// Get actual HAL format.
status_t result = mOutput->stream->getFormat(&mHALFormat);
@ -2642,7 +2649,7 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l()
free(mMixerBuffer);
mMixerBuffer = NULL;
if (mMixerBufferEnabled) {
mMixerBufferFormat = AUDIO_FORMAT_PCM_FLOAT; // also valid: AUDIO_FORMAT_PCM_16_BIT.
mMixerBufferFormat = AUDIO_FORMAT_PCM_FLOAT; // no longer valid: AUDIO_FORMAT_PCM_16_BIT.
mMixerBufferSize = mNormalFrameCount * mChannelCount
* audio_bytes_per_sample(mMixerBufferFormat);
(void)posix_memalign(&mMixerBuffer, 32, mMixerBufferSize);
@ -3531,6 +3538,14 @@ bool AudioFlinger::PlaybackThread::threadLoop()
true /*limit*/);
}
if (!hasFastMixer()) {
// Balance must take effect after mono conversion.
// We do it here if there is no FastMixer.
// mBalance detects zero balance within the class for speed (not needed here).
mBalance.setBalance(mMasterBalance.load());
mBalance.process((float *)mMixerBuffer, mNormalFrameCount);
}
memcpy_by_audio_format(buffer, format, mMixerBuffer, mMixerBufferFormat,
mNormalFrameCount * (mChannelCount + mHapticChannelCount));
@ -3585,6 +3600,14 @@ bool AudioFlinger::PlaybackThread::threadLoop()
true /*limit*/);
}
if (!hasFastMixer()) {
// Balance must take effect after mono conversion.
// We do it here if there is no FastMixer.
// mBalance detects zero balance within the class for speed (not needed here).
mBalance.setBalance(mMasterBalance.load());
mBalance.process((float *)mEffectBuffer, mNormalFrameCount);
}
memcpy_by_audio_format(mSinkBuffer, mFormat, mEffectBuffer, mEffectBufferFormat,
mNormalFrameCount * (mChannelCount + mHapticChannelCount));
// The sample data is partially interleaved when haptic channels exist,
@ -3985,6 +4008,7 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud
// mPipeSink below
// mNormalSink below
{
setMasterBalance(audioFlinger->getMasterBalance_l());
ALOGV("MixerThread() id=%d device=%#x type=%d", id, device, type);
ALOGV("mSampleRate=%u, mChannelMask=%#x, mChannelCount=%u, mFormat=%#x, mFrameSize=%zu, "
"mFrameCount=%zu, mNormalFrameCount=%zu",
@ -5266,6 +5290,9 @@ void AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& ar
dprintf(fd, " Thread throttle time (msecs): %u\n", mThreadThrottleTimeMs);
dprintf(fd, " AudioMixer tracks: %s\n", mAudioMixer->trackNames().c_str());
dprintf(fd, " Master mono: %s\n", mMasterMono ? "on" : "off");
dprintf(fd, " Master balance: %f (%s)\n", mMasterBalance.load(),
(hasFastMixer() ? std::to_string(mFastMixer->getMasterBalance())
: mBalance.toString()).c_str());
const double latencyMs = mTimestamp.getOutputServerLatencyMs(mSampleRate);
if (latencyMs != 0.) {
dprintf(fd, " NormalMixer latency ms: %.2lf\n", latencyMs);
@ -5333,12 +5360,30 @@ AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& aud
ThreadBase::type_t type, bool systemReady)
: PlaybackThread(audioFlinger, output, id, device, type, systemReady)
{
setMasterBalance(audioFlinger->getMasterBalance_l());
}
AudioFlinger::DirectOutputThread::~DirectOutputThread()
{
}
void AudioFlinger::DirectOutputThread::dumpInternals(int fd, const Vector<String16>& args)
{
PlaybackThread::dumpInternals(fd, args);
dprintf(fd, " Master balance: %f Left: %f Right: %f\n",
mMasterBalance.load(), mMasterBalanceLeft, mMasterBalanceRight);
}
void AudioFlinger::DirectOutputThread::setMasterBalance(float balance)
{
Mutex::Autolock _l(mLock);
if (mMasterBalance != balance) {
mMasterBalance.store(balance);
mBalance.computeStereoBalance(balance, &mMasterBalanceLeft, &mMasterBalanceRight);
broadcast_l();
}
}
void AudioFlinger::DirectOutputThread::processVolume_l(Track *track, bool lastTrack)
{
float left, right;
@ -5362,12 +5407,12 @@ void AudioFlinger::DirectOutputThread::processVolume_l(Track *track, bool lastTr
if (left > GAIN_FLOAT_UNITY) {
left = GAIN_FLOAT_UNITY;
}
left *= v;
left *= v * mMasterBalanceLeft; // DirectOutputThread balance applied as track volume
right = float_from_gain(gain_minifloat_unpack_right(vlr));
if (right > GAIN_FLOAT_UNITY) {
right = GAIN_FLOAT_UNITY;
}
right *= v;
right *= v * mMasterBalanceRight;
}
if (lastTrack) {

@ -733,6 +733,7 @@ public:
// VolumeInterface
virtual void setMasterVolume(float value);
virtual void setMasterBalance(float balance);
virtual void setMasterMute(bool muted);
virtual void setStreamVolume(audio_stream_type_t stream, float value);
virtual void setStreamMute(audio_stream_type_t stream, bool muted);
@ -1027,6 +1028,8 @@ private:
AudioStreamOut *mOutput;
float mMasterVolume;
std::atomic<float> mMasterBalance{};
audio_utils::Balance mBalance;
nsecs_t mLastWriteTime;
int mNumWrites;
int mNumDelayedWrites;
@ -1199,6 +1202,13 @@ protected:
// Blending with limiter is not idempotent,
// and blending without limiter is idempotent but inefficient to do twice.
virtual bool requireMonoBlend() { return mMasterMono.load() && !hasFastMixer(); }
void setMasterBalance(float balance) override {
mMasterBalance.store(balance);
if (hasFastMixer()) {
mFastMixer->setMasterBalance(balance);
}
}
};
class DirectOutputThread : public PlaybackThread {
@ -1216,8 +1226,13 @@ public:
virtual bool checkForNewParameter_l(const String8& keyValuePair,
status_t& status);
void dumpInternals(int fd, const Vector<String16>& args) override;
virtual void flushHw_l();
void setMasterBalance(float balance) override;
protected:
virtual uint32_t activeSleepTimeUs() const;
virtual uint32_t idleSleepTimeUs() const;
@ -1245,6 +1260,10 @@ protected:
wp<Track> mPreviousTrack; // used to detect track switch
// This must be initialized for initial condition of mMasterBalance = 0 (disabled).
float mMasterBalanceLeft = 1.f;
float mMasterBalanceRight = 1.f;
public:
virtual bool hasFastMixer() const { return false; }

Loading…
Cancel
Save