From c56f3426099a3cf2d07ccff8886050c7fbce140f Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 21 Mar 2014 17:53:17 -0700 Subject: Pass stereo gains as packed minifloat This will allow (eventually) a greater dynamic range for gains. However there are still a few remaining places in effects and mixer that will also need to be changed in order to get the full benefit. Also fixes a minor bug: was not checking for NaN in AudioTrack C++. Change-Id: I63bce9e82e0a61546d8ff475fb94bcb700d99c96 --- include/private/media/AudioTrackShared.h | 14 +++++----- media/libmedia/AudioTrack.cpp | 13 ++++++---- media/libmedia/AudioTrackShared.cpp | 2 +- media/mediaserver/Android.mk | 3 ++- services/audioflinger/AudioFlinger.h | 3 --- services/audioflinger/AudioMixer.h | 4 +++ services/audioflinger/Effects.h | 1 + services/audioflinger/FastMixer.cpp | 12 +++++---- services/audioflinger/FastMixerState.h | 6 ++--- services/audioflinger/PlaybackTracks.h | 2 +- services/audioflinger/Threads.cpp | 44 +++++++++++++++++++------------- services/audioflinger/Tracks.cpp | 29 +++++++++++---------- 12 files changed, 74 insertions(+), 59 deletions(-) diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h index 3901e79..5116d1e 100644 --- a/include/private/media/AudioTrackShared.h +++ b/include/private/media/AudioTrackShared.h @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -110,11 +111,8 @@ private: // force to 32-bit. The client and server may have different typedefs for size_t. uint32_t mMinimum; // server wakes up client if available >= mMinimum - // Channel volumes are fixed point U4.12, so 0x1000 means 1.0. - // Left channel is in [0:15], right channel is in [16:31]. - // Always read and write the combined pair atomically. - // For AudioTrack only, not used by AudioRecord. - uint32_t mVolumeLR; + // Stereo gains for AudioTrack only, not used by AudioRecord. + gain_minifloat_packed_t mVolumeLR; uint32_t mSampleRate; // AudioTrack only: client's requested sample rate in Hz // or 0 == default. Write-only client, read-only server. @@ -285,8 +283,8 @@ public: mCblk->mSendLevel = uint16_t(sendLevel * 0x1000); } - // caller must limit to 0 <= volumeLR <= 0x10001000 - void setVolumeLR(uint32_t volumeLR) { + // set stereo gains + void setVolumeLR(gain_minifloat_packed_t volumeLR) { mCblk->mVolumeLR = volumeLR; } @@ -405,7 +403,7 @@ public: // return value of these methods must be validated by the caller uint32_t getSampleRate() const { return mCblk->mSampleRate; } uint16_t getSendLevel_U4_12() const { return mCblk->mSendLevel; } - uint32_t getVolumeLR() const { return mCblk->mVolumeLR; } + gain_minifloat_packed_t getVolumeLR() const { return mCblk->mVolumeLR; } // estimated total number of filled frames available to server to read, // which may include non-contiguous frames diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index aaaa3f1..120b28e 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -19,6 +19,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "AudioTrack" +#include #include #include #include @@ -566,7 +567,9 @@ void AudioTrack::pause() status_t AudioTrack::setVolume(float left, float right) { - if (left < 0.0f || left > 1.0f || right < 0.0f || right > 1.0f) { + // This duplicates a test by AudioTrack JNI, but that is not the only caller + if (isnanf(left) || left < GAIN_FLOAT_ZERO || left > GAIN_FLOAT_UNITY || + isnanf(right) || right < GAIN_FLOAT_ZERO || right > GAIN_FLOAT_UNITY) { return BAD_VALUE; } @@ -574,7 +577,7 @@ status_t AudioTrack::setVolume(float left, float right) mVolume[AUDIO_INTERLEAVE_LEFT] = left; mVolume[AUDIO_INTERLEAVE_RIGHT] = right; - mProxy->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000)); + mProxy->setVolumeLR(gain_minifloat_pack(gain_from_float(left), gain_from_float(right))); if (isOffloaded_l()) { mAudioTrack->signal(); @@ -589,7 +592,8 @@ status_t AudioTrack::setVolume(float volume) status_t AudioTrack::setAuxEffectSendLevel(float level) { - if (level < 0.0f || level > 1.0f) { + // This duplicates a test by AudioTrack JNI, but that is not the only caller + if (isnanf(level) || level < GAIN_FLOAT_ZERO || level > GAIN_FLOAT_UNITY) { return BAD_VALUE; } @@ -1137,8 +1141,7 @@ status_t AudioTrack::createTrack_l(size_t epoch) mStaticProxy = new StaticAudioTrackClientProxy(cblk, buffers, frameCount, mFrameSizeAF); mProxy = mStaticProxy; } - mProxy->setVolumeLR((uint32_t(uint16_t(mVolume[AUDIO_INTERLEAVE_RIGHT] * 0x1000)) << 16) | - uint16_t(mVolume[AUDIO_INTERLEAVE_LEFT] * 0x1000)); + mProxy->setVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY); mProxy->setSendLevel(mSendLevel); mProxy->setSampleRate(mSampleRate); mProxy->setEpoch(epoch); diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp index 323b675..27a3718 100644 --- a/media/libmedia/AudioTrackShared.cpp +++ b/media/libmedia/AudioTrackShared.cpp @@ -27,7 +27,7 @@ namespace android { audio_track_cblk_t::audio_track_cblk_t() : mServer(0), mFutex(0), mMinimum(0), - mVolumeLR(0x10001000), mSampleRate(0), mSendLevel(0), mFlags(0) + mVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY), mSampleRate(0), mSendLevel(0), mFlags(0) { memset(&u, 0, sizeof(u)); } diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk index d3e546a..5bc3f2f 100644 --- a/media/mediaserver/Android.mk +++ b/media/mediaserver/Android.mk @@ -35,7 +35,8 @@ LOCAL_C_INCLUDES := \ frameworks/av/services/medialog \ frameworks/av/services/audioflinger \ frameworks/av/services/audiopolicy \ - frameworks/av/services/camera/libcameraservice + frameworks/av/services/camera/libcameraservice \ + $(call include-path-for, audio-utils) LOCAL_MODULE:= mediaserver LOCAL_32_BIT_ONLY := true diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index d69d6a2..d2ded9a 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -82,9 +82,6 @@ class ServerProxy; static const nsecs_t kDefaultStandbyTimeInNsecs = seconds(3); -#define MAX_GAIN 4096.0f -#define MAX_GAIN_INT 0x1000 - #define INCLUDING_FROM_AUDIOFLINGER_H class AudioFlinger : diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h index e5e120c..09e63a6 100644 --- a/services/audioflinger/AudioMixer.h +++ b/services/audioflinger/AudioMixer.h @@ -30,6 +30,9 @@ #include #include +// FIXME This is actually unity gain, which might not be max in future, expressed in U.12 +#define MAX_GAIN_INT AudioMixer::UNITY_GAIN + namespace android { // ---------------------------------------------------------------------------- @@ -91,6 +94,7 @@ public: REMOVE = 0x4102, // Remove the sample rate converter on this track name; // the track is restored to the mix sample rate. // for target RAMP_VOLUME and VOLUME (8 channels max) + // FIXME use float for these 3 to improve the dynamic range VOLUME0 = 0x4200, VOLUME1 = 0x4201, AUXLEVEL = 0x4210, diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h index ccc4825..4170fd4 100644 --- a/services/audioflinger/Effects.h +++ b/services/audioflinger/Effects.h @@ -270,6 +270,7 @@ public: sp getEffectFromDesc_l(effect_descriptor_t *descriptor); sp getEffectFromId_l(int id); sp getEffectFromType_l(const effect_uuid_t *type); + // FIXME use float to improve the dynamic range bool setVolume_l(uint32_t *left, uint32_t *right); void setDevice_l(audio_devices_t device); void setMode_l(audio_mode_t mode); diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp index 5cb42cc..42ba791 100644 --- a/services/audioflinger/FastMixer.cpp +++ b/services/audioflinger/FastMixer.cpp @@ -257,9 +257,9 @@ void FastMixer::onStateChange() mixer->setBufferProvider(name, bufferProvider); if (fastTrack->mVolumeProvider == NULL) { mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, - (void *)0x1000); + (void *) MAX_GAIN_INT); mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, - (void *)0x1000); + (void *) MAX_GAIN_INT); } mixer->setParameter(name, AudioMixer::RESAMPLE, AudioMixer::REMOVE, NULL); @@ -312,11 +312,13 @@ void FastMixer::onWork() int name = fastTrackNames[i]; ALOG_ASSERT(name >= 0); if (fastTrack->mVolumeProvider != NULL) { - uint32_t vlr = fastTrack->mVolumeProvider->getVolumeLR(); + gain_minifloat_packed_t vlr = fastTrack->mVolumeProvider->getVolumeLR(); mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, - (void *)(uintptr_t)(vlr & 0xFFFF)); + (void *) (uintptr_t) + (float_from_gain(gain_minifloat_unpack_left(vlr)) * MAX_GAIN_INT)); mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, - (void *)(uintptr_t)(vlr >> 16)); + (void *) (uintptr_t) + (float_from_gain(gain_minifloat_unpack_right(vlr)) * MAX_GAIN_INT)); } // FIXME The current implementation of framesReady() for fast tracks // takes a tryLock, which can block diff --git a/services/audioflinger/FastMixerState.h b/services/audioflinger/FastMixerState.h index be1a376..e388fb3 100644 --- a/services/audioflinger/FastMixerState.h +++ b/services/audioflinger/FastMixerState.h @@ -17,6 +17,7 @@ #ifndef ANDROID_AUDIO_FAST_MIXER_STATE_H #define ANDROID_AUDIO_FAST_MIXER_STATE_H +#include #include #include #include @@ -29,9 +30,8 @@ struct FastMixerDumpState; class VolumeProvider { public: - // Return the track volume in U4_12 format: left in lower half, right in upper half. The - // provider implementation is responsible for validating that the return value is in range. - virtual uint32_t getVolumeLR() = 0; + // The provider implementation is responsible for validating that the return value is in range. + virtual gain_minifloat_packed_t getVolumeLR() = 0; protected: VolumeProvider() { } virtual ~VolumeProvider() { } diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h index 08b1728..6f1f293 100644 --- a/services/audioflinger/PlaybackTracks.h +++ b/services/audioflinger/PlaybackTracks.h @@ -65,7 +65,7 @@ public: void signal(); // implement FastMixerState::VolumeProvider interface - virtual uint32_t getVolumeLR(); + virtual gain_minifloat_packed_t getVolumeLR(); virtual status_t setSyncEvent(const sp& event); diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 2d4e025..5cb6a09 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -35,6 +35,7 @@ #include #include #include +#include // NBAIO implementations #include @@ -3255,21 +3256,23 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac float typeVolume = mStreamTypes[track->streamType()].volume; float v = masterVolume * typeVolume; AudioTrackServerProxy *proxy = track->mAudioTrackServerProxy; - uint32_t vlr = proxy->getVolumeLR(); - vl = vlr & 0xFFFF; - vr = vlr >> 16; + gain_minifloat_packed_t vlr = proxy->getVolumeLR(); + float vlf = float_from_gain(gain_minifloat_unpack_left(vlr)); + float vrf = float_from_gain(gain_minifloat_unpack_right(vlr)); // track volumes come from shared memory, so can't be trusted and must be clamped - if (vl > MAX_GAIN_INT) { - ALOGV("Track left volume out of range: %04X", vl); - vl = MAX_GAIN_INT; + if (vlf > GAIN_FLOAT_UNITY) { + ALOGV("Track left volume out of range: %.3g", vlf); + vlf = GAIN_FLOAT_UNITY; } - if (vr > MAX_GAIN_INT) { - ALOGV("Track right volume out of range: %04X", vr); - vr = MAX_GAIN_INT; + if (vrf > GAIN_FLOAT_UNITY) { + ALOGV("Track right volume out of range: %.3g", vrf); + vrf = GAIN_FLOAT_UNITY; } // now apply the master volume and stream type volume - vl = (uint32_t)(v * vl) << 12; - vr = (uint32_t)(v * vr) << 12; + // FIXME we're losing the wonderful dynamic range in the minifloat representation + float v8_24 = v * (MAX_GAIN_INT * MAX_GAIN_INT); + vl = (uint32_t) (v8_24 * vlf); + vr = (uint32_t) (v8_24 * vrf); // assuming master volume and stream type volume each go up to 1.0, // vl and vr are now in 8.24 format @@ -3296,6 +3299,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac track->mHasVolumeController = false; } + // FIXME Use float // Convert volumes from 8.24 to 4.12 format // This additional clamping is needed in case chain->setVolume_l() overshot vl = (vl + (1 << 11)) >> 12; @@ -3750,13 +3754,17 @@ void AudioFlinger::DirectOutputThread::processVolume_l(Track *track, bool lastTr float typeVolume = mStreamTypes[track->streamType()].volume; float v = mMasterVolume * typeVolume; AudioTrackServerProxy *proxy = track->mAudioTrackServerProxy; - uint32_t vlr = proxy->getVolumeLR(); - float v_clamped = v * (vlr & 0xFFFF); - if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN; - left = v_clamped/MAX_GAIN; - v_clamped = v * (vlr >> 16); - if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN; - right = v_clamped/MAX_GAIN; + gain_minifloat_packed_t vlr = proxy->getVolumeLR(); + left = float_from_gain(gain_minifloat_unpack_left(vlr)); + if (left > GAIN_FLOAT_UNITY) { + left = GAIN_FLOAT_UNITY; + } + left *= v; + right = float_from_gain(gain_minifloat_unpack_right(vlr)); + if (right > GAIN_FLOAT_UNITY) { + right = GAIN_FLOAT_UNITY; + } + right *= v; } if (lastTrack) { diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index 6dc7f30..08687a2 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -34,6 +34,7 @@ #include #include +#include // ---------------------------------------------------------------------------- @@ -459,7 +460,7 @@ void AudioFlinger::PlaybackThread::Track::destroy() void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size, bool active) { - uint32_t vlr = mAudioTrackServerProxy->getVolumeLR(); + gain_minifloat_packed_t vlr = mAudioTrackServerProxy->getVolumeLR(); if (isFastTrack()) { sprintf(buffer, " F %2d", mFastIndex); } else if (mName >= AudioMixer::TRACK0) { @@ -532,8 +533,8 @@ void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size, bool a stateChar, mFillingUpStatus, mAudioTrackServerProxy->getSampleRate(), - 20.0 * log10((vlr & 0xFFFF) / 4096.0), - 20.0 * log10((vlr >> 16) / 4096.0), + 20.0 * log10(float_from_gain(gain_minifloat_unpack_left(vlr))), + 20.0 * log10(float_from_gain(gain_minifloat_unpack_right(vlr))), mCblk->mServer, mMainBuffer, mAuxBuffer, @@ -959,27 +960,27 @@ void AudioFlinger::PlaybackThread::Track::triggerEvents(AudioSystem::sync_event_ // implement VolumeBufferProvider interface -uint32_t AudioFlinger::PlaybackThread::Track::getVolumeLR() +gain_minifloat_packed_t AudioFlinger::PlaybackThread::Track::getVolumeLR() { // called by FastMixer, so not allowed to take any locks, block, or do I/O including logs ALOG_ASSERT(isFastTrack() && (mCblk != NULL)); - uint32_t vlr = mAudioTrackServerProxy->getVolumeLR(); - uint32_t vl = vlr & 0xFFFF; - uint32_t vr = vlr >> 16; + gain_minifloat_packed_t vlr = mAudioTrackServerProxy->getVolumeLR(); + float vl = float_from_gain(gain_minifloat_unpack_left(vlr)); + float vr = float_from_gain(gain_minifloat_unpack_right(vlr)); // track volumes come from shared memory, so can't be trusted and must be clamped - if (vl > MAX_GAIN_INT) { - vl = MAX_GAIN_INT; + if (vl > GAIN_FLOAT_UNITY) { + vl = GAIN_FLOAT_UNITY; } - if (vr > MAX_GAIN_INT) { - vr = MAX_GAIN_INT; + if (vr > GAIN_FLOAT_UNITY) { + vr = GAIN_FLOAT_UNITY; } // now apply the cached master volume and stream type volume; // this is trusted but lacks any synchronization or barrier so may be stale float v = mCachedVolume; vl *= v; vr *= v; - // re-combine into U4.16 - vlr = (vr << 16) | (vl & 0xFFFF); + // re-combine into packed minifloat + vlr = gain_minifloat_pack(gain_from_float(vl), gain_from_float(vr)); // FIXME look at mute, pause, and stop flags return vlr; } @@ -1590,7 +1591,7 @@ AudioFlinger::PlaybackThread::OutputTrack::OutputTrack( // since client and server are in the same process, // the buffer has the same virtual address on both sides mClientProxy = new AudioTrackClientProxy(mCblk, mBuffer, mFrameCount, mFrameSize); - mClientProxy->setVolumeLR((uint32_t(uint16_t(0x1000)) << 16) | uint16_t(0x1000)); + mClientProxy->setVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY); mClientProxy->setSendLevel(0.0); mClientProxy->setSampleRate(sampleRate); mClientProxy = new AudioTrackClientProxy(mCblk, mBuffer, mFrameCount, mFrameSize, -- cgit v1.1