diff options
Diffstat (limited to 'services/audioflinger')
50 files changed, 2513 insertions, 1820 deletions
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk index 697fb37..642ff82 100644 --- a/services/audioflinger/Android.mk +++ b/services/audioflinger/Android.mk @@ -19,10 +19,22 @@ LOCAL_SRC_FILES := \ # FIXME Move this library to frameworks/native LOCAL_MODULE := libserviceutility -include $(BUILD_STATIC_LIBRARY) +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libutils \ + liblog \ + libbinder + +include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) +# Clang++ aborts on AudioMixer.cpp, +# b/18373866, "do not know how to split this operator." +ifeq ($(filter $(TARGET_ARCH),arm arm64),$(TARGET_ARCH)) + LOCAL_CLANG := false +endif + LOCAL_SRC_FILES:= \ AudioFlinger.cpp \ Threads.cpp \ @@ -51,30 +63,31 @@ LOCAL_SHARED_LIBRARIES := \ libhardware \ libhardware_legacy \ libeffects \ - libpowermanager + libpowermanager \ + libserviceutility LOCAL_STATIC_LIBRARIES := \ libscheduling_policy \ libcpustats \ - libmedia_helper \ - libserviceutility + libmedia_helper LOCAL_MODULE:= libaudioflinger LOCAL_32_BIT_ONLY := true -LOCAL_SRC_FILES += FastMixer.cpp FastMixerState.cpp AudioWatchdog.cpp -LOCAL_SRC_FILES += FastThread.cpp FastThreadState.cpp -LOCAL_SRC_FILES += FastCapture.cpp FastCaptureState.cpp +LOCAL_SRC_FILES += \ + AudioWatchdog.cpp \ + FastCapture.cpp \ + FastCaptureDumpState.cpp \ + FastCaptureState.cpp \ + FastMixer.cpp \ + FastMixerDumpState.cpp \ + FastMixerState.cpp \ + FastThread.cpp \ + FastThreadDumpState.cpp \ + FastThreadState.cpp LOCAL_CFLAGS += -DSTATE_QUEUE_INSTANTIATIONS='"StateQueueInstantiations.cpp"' -# Define ANDROID_SMP appropriately. Used to get inline tracing fast-path. -ifeq ($(TARGET_CPU_SMP),true) - LOCAL_CFLAGS += -DANDROID_SMP=1 -else - LOCAL_CFLAGS += -DANDROID_SMP=0 -endif - LOCAL_CFLAGS += -fvisibility=hidden include $(BUILD_SHARED_LIBRARY) diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 115b60c..461b5d3 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -185,7 +185,8 @@ AudioFlinger::AudioFlinger() char value[PROPERTY_VALUE_MAX]; bool doLog = (property_get("ro.test_harness", value, "0") > 0) && (atoi(value) == 1); if (doLog) { - mLogMemoryDealer = new MemoryDealer(kLogMemorySize, "LogWriters", MemoryHeapBase::READ_ONLY); + mLogMemoryDealer = new MemoryDealer(kLogMemorySize, "LogWriters", + MemoryHeapBase::READ_ONLY); } #ifdef TEE_SINK @@ -825,14 +826,20 @@ bool AudioFlinger::getMicMute() const if (ret != NO_ERROR) { return false; } - + bool mute = true; bool state = AUDIO_MODE_INVALID; AutoMutex lock(mHardwareLock); - audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice(); mHardwareStatus = AUDIO_HW_GET_MIC_MUTE; - dev->get_mic_mute(dev, &state); + for (size_t i = 0; i < mAudioHwDevs.size(); i++) { + audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice(); + status_t result = dev->get_mic_mute(dev, &state); + if (result == NO_ERROR) { + mute = mute && state; + } + } mHardwareStatus = AUDIO_HW_IDLE; - return state; + + return mute; } status_t AudioFlinger::setMasterMute(bool muted) @@ -894,6 +901,21 @@ bool AudioFlinger::masterMute_l() const return mMasterMute; } +status_t AudioFlinger::checkStreamType(audio_stream_type_t stream) const +{ + if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + ALOGW("setStreamVolume() invalid stream %d", stream); + return BAD_VALUE; + } + pid_t caller = IPCThreadState::self()->getCallingPid(); + if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT && caller != getpid_cached) { + ALOGW("setStreamVolume() pid %d cannot use internal stream type %d", caller, stream); + return PERMISSION_DENIED; + } + + return NO_ERROR; +} + status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value, audio_io_handle_t output) { @@ -902,10 +924,11 @@ status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value, return PERMISSION_DENIED; } - if (uint32_t(stream) >= AUDIO_STREAM_CNT) { - ALOGE("setStreamVolume() invalid stream %d", stream); - return BAD_VALUE; + status_t status = checkStreamType(stream); + if (status != NO_ERROR) { + return status; } + ALOG_ASSERT(stream != AUDIO_STREAM_PATCH, "attempt to change AUDIO_STREAM_PATCH volume"); AutoMutex lock(mLock); PlaybackThread *thread = NULL; @@ -936,8 +959,13 @@ status_t AudioFlinger::setStreamMute(audio_stream_type_t stream, bool muted) return PERMISSION_DENIED; } - if (uint32_t(stream) >= AUDIO_STREAM_CNT || - uint32_t(stream) == AUDIO_STREAM_ENFORCED_AUDIBLE) { + status_t status = checkStreamType(stream); + if (status != NO_ERROR) { + return status; + } + ALOG_ASSERT(stream != AUDIO_STREAM_PATCH, "attempt to mute AUDIO_STREAM_PATCH"); + + if (uint32_t(stream) == AUDIO_STREAM_ENFORCED_AUDIBLE) { ALOGE("setStreamMute() invalid stream %d", stream); return BAD_VALUE; } @@ -952,7 +980,8 @@ status_t AudioFlinger::setStreamMute(audio_stream_type_t stream, bool muted) float AudioFlinger::streamVolume(audio_stream_type_t stream, audio_io_handle_t output) const { - if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + status_t status = checkStreamType(stream); + if (status != NO_ERROR) { return 0.0f; } @@ -973,7 +1002,8 @@ float AudioFlinger::streamVolume(audio_stream_type_t stream, audio_io_handle_t o bool AudioFlinger::streamMute(audio_stream_type_t stream) const { - if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + status_t status = checkStreamType(stream); + if (status != NO_ERROR) { return true; } @@ -1191,7 +1221,7 @@ void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client) mNotificationClients.add(pid, notificationClient); - sp<IBinder> binder = client->asBinder(); + sp<IBinder> binder = IInterface::asBinder(client); binder->linkToDeath(notificationClient); clientAdded = true; } @@ -1413,13 +1443,6 @@ sp<IAudioRecord> AudioFlinger::openRecord( goto Exit; } - if (deviceRequiresCaptureAudioOutputPermission(thread->inDevice()) - && !captureAudioOutputAllowed()) { - ALOGE("openRecord() permission denied: capture not allowed"); - lStatus = PERMISSION_DENIED; - goto Exit; - } - pid_t pid = IPCThreadState::self()->getCallingPid(); client = registerPid(pid); @@ -1934,18 +1957,18 @@ status_t AudioFlinger::restoreOutput(audio_io_handle_t output) status_t AudioFlinger::openInput(audio_module_handle_t module, audio_io_handle_t *input, audio_config_t *config, - audio_devices_t *device, + audio_devices_t *devices, const String8& address, audio_source_t source, audio_input_flags_t flags) { Mutex::Autolock _l(mLock); - if (*device == AUDIO_DEVICE_NONE) { + if (*devices == AUDIO_DEVICE_NONE) { return BAD_VALUE; } - sp<RecordThread> thread = openInput_l(module, input, config, *device, address, source, flags); + sp<RecordThread> thread = openInput_l(module, input, config, *devices, address, source, flags); if (thread != 0) { // notify client processes of the new input creation @@ -1958,12 +1981,12 @@ status_t AudioFlinger::openInput(audio_module_handle_t module, sp<AudioFlinger::RecordThread> AudioFlinger::openInput_l(audio_module_handle_t module, audio_io_handle_t *input, audio_config_t *config, - audio_devices_t device, + audio_devices_t devices, const String8& address, audio_source_t source, audio_input_flags_t flags) { - AudioHwDevice *inHwDev = findSuitableHwDev_l(module, device); + AudioHwDevice *inHwDev = findSuitableHwDev_l(module, devices); if (inHwDev == NULL) { *input = AUDIO_IO_HANDLE_NONE; return 0; @@ -1976,7 +1999,7 @@ sp<AudioFlinger::RecordThread> AudioFlinger::openInput_l(audio_module_handle_t m audio_config_t halconfig = *config; audio_hw_device_t *inHwHal = inHwDev->hwDevice(); audio_stream_in_t *inStream = NULL; - status_t status = inHwHal->open_input_stream(inHwHal, *input, device, &halconfig, + status_t status = inHwHal->open_input_stream(inHwHal, *input, devices, &halconfig, &inStream, flags, address.string(), source); ALOGV("openInput_l() openInputStream returned input %p, SamplingRate %d" ", Format %#x, Channels %x, flags %#x, status %d addr %s", @@ -1998,7 +2021,7 @@ sp<AudioFlinger::RecordThread> AudioFlinger::openInput_l(audio_module_handle_t m // FIXME describe the change proposed by HAL (save old values so we can log them here) ALOGV("openInput_l() reopening with proposed sampling rate and channel mask"); inStream = NULL; - status = inHwHal->open_input_stream(inHwHal, *input, device, &halconfig, + status = inHwHal->open_input_stream(inHwHal, *input, devices, &halconfig, &inStream, flags, address.string(), source); // FIXME log this new status; HAL should not propose any further changes } @@ -2063,7 +2086,7 @@ sp<AudioFlinger::RecordThread> AudioFlinger::openInput_l(audio_module_handle_t m inputStream, *input, primaryOutputDevice_l(), - device + devices #ifdef TEE_SINK , teeSink #endif @@ -2786,13 +2809,13 @@ bool AudioFlinger::updateOrphanEffectChains(const sp<AudioFlinger::EffectModule> struct Entry { -#define MAX_NAME 32 // %Y%m%d%H%M%S_%d.wav - char mName[MAX_NAME]; +#define TEE_MAX_FILENAME 32 // %Y%m%d%H%M%S_%d.wav = 4+2+2+2+2+2+1+1+4+1 = 21 + char mFileName[TEE_MAX_FILENAME]; }; int comparEntry(const void *p1, const void *p2) { - return strcmp(((const Entry *) p1)->mName, ((const Entry *) p2)->mName); + return strcmp(((const Entry *) p1)->mFileName, ((const Entry *) p2)->mFileName); } #ifdef TEE_SINK @@ -2811,11 +2834,11 @@ void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_hand DIR *dir = opendir(teePath); teePath[teePathLen++] = '/'; if (dir != NULL) { -#define MAX_SORT 20 // number of entries to sort -#define MAX_KEEP 10 // number of entries to keep - struct Entry entries[MAX_SORT]; +#define TEE_MAX_SORT 20 // number of entries to sort +#define TEE_MAX_KEEP 10 // number of entries to keep + struct Entry entries[TEE_MAX_SORT]; size_t entryCount = 0; - while (entryCount < MAX_SORT) { + while (entryCount < TEE_MAX_SORT) { struct dirent de; struct dirent *result = NULL; int rc = readdir_r(dir, &de, &result); @@ -2832,17 +2855,17 @@ void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_hand } // ignore non .wav file entries size_t nameLen = strlen(de.d_name); - if (nameLen <= 4 || nameLen >= MAX_NAME || + if (nameLen <= 4 || nameLen >= TEE_MAX_FILENAME || strcmp(&de.d_name[nameLen - 4], ".wav")) { continue; } - strcpy(entries[entryCount++].mName, de.d_name); + strcpy(entries[entryCount++].mFileName, de.d_name); } (void) closedir(dir); - if (entryCount > MAX_KEEP) { + if (entryCount > TEE_MAX_KEEP) { qsort(entries, entryCount, sizeof(Entry), comparEntry); - for (size_t i = 0; i < entryCount - MAX_KEEP; ++i) { - strcpy(&teePath[teePathLen], entries[i].mName); + for (size_t i = 0; i < entryCount - TEE_MAX_KEEP; ++i) { + strcpy(&teePath[teePathLen], entries[i].mFileName); (void) unlink(teePath); } } @@ -2926,4 +2949,4 @@ status_t AudioFlinger::onTransact( return BnAudioFlinger::onTransact(code, data, reply, flags); } -}; // namespace android +} // namespace android diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 4fb372d..7b76185 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -745,6 +745,8 @@ private: void closeInputInternal_l(sp<RecordThread> thread); void setAudioHwSyncForSession_l(PlaybackThread *thread, audio_session_t sessionId); + status_t checkStreamType(audio_stream_type_t stream) const; + #ifdef TEE_SINK // all record threads serially share a common tee sink, which is re-created on format change sp<NBAIO_Sink> mRecordTeeSink; @@ -794,9 +796,13 @@ private: #undef INCLUDING_FROM_AUDIOFLINGER_H const char *formatToString(audio_format_t format); +String8 inputFlagsToString(audio_input_flags_t flags); +String8 outputFlagsToString(audio_output_flags_t flags); +String8 devicesToString(audio_devices_t devices); +const char *sourceToString(audio_source_t source); // ---------------------------------------------------------------------------- -}; // namespace android +} // namespace android #endif // ANDROID_AUDIO_FLINGER_H diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp index 247f728..dddca02 100644 --- a/services/audioflinger/AudioMixer.cpp +++ b/services/audioflinger/AudioMixer.cpp @@ -341,11 +341,46 @@ AudioMixer::RemixBufferProvider::RemixBufferProvider(audio_channel_mask_t inputC ALOGV("RemixBufferProvider(%p)(%#x, %#x, %#x) %zu %zu", this, format, inputChannelMask, outputChannelMask, mInputChannels, mOutputChannels); - // TODO: consider channel representation in index array formulation - // We ignore channel representation, and just use the bits. - memcpy_by_index_array_initialization(mIdxAry, ARRAY_SIZE(mIdxAry), - audio_channel_mask_get_bits(outputChannelMask), - audio_channel_mask_get_bits(inputChannelMask)); + + const audio_channel_representation_t inputRepresentation = + audio_channel_mask_get_representation(inputChannelMask); + const audio_channel_representation_t outputRepresentation = + audio_channel_mask_get_representation(outputChannelMask); + const uint32_t inputBits = audio_channel_mask_get_bits(inputChannelMask); + const uint32_t outputBits = audio_channel_mask_get_bits(outputChannelMask); + + switch (inputRepresentation) { + case AUDIO_CHANNEL_REPRESENTATION_POSITION: + switch (outputRepresentation) { + case AUDIO_CHANNEL_REPRESENTATION_POSITION: + memcpy_by_index_array_initialization(mIdxAry, ARRAY_SIZE(mIdxAry), + outputBits, inputBits); + return; + case AUDIO_CHANNEL_REPRESENTATION_INDEX: + // TODO: output channel index mask not currently allowed + // fall through + default: + break; + } + break; + case AUDIO_CHANNEL_REPRESENTATION_INDEX: + switch (outputRepresentation) { + case AUDIO_CHANNEL_REPRESENTATION_POSITION: + memcpy_by_index_array_initialization_src_index(mIdxAry, ARRAY_SIZE(mIdxAry), + outputBits, inputBits); + return; + case AUDIO_CHANNEL_REPRESENTATION_INDEX: + // TODO: output channel index mask not currently allowed + // fall through + default: + break; + } + break; + default: + break; + } + LOG_ALWAYS_FATAL("invalid channel mask conversion from %#x to %#x", + inputChannelMask, outputChannelMask); } void AudioMixer::RemixBufferProvider::copyFrames(void *dst, const void *src, size_t frames) @@ -605,7 +640,10 @@ status_t AudioMixer::track_t::prepareForDownmix() && mMixerChannelMask == AUDIO_CHANNEL_OUT_STEREO)) { return NO_ERROR; } - if (DownmixerBufferProvider::isMultichannelCapable()) { + // DownmixerBufferProvider is only used for position masks. + if (audio_channel_mask_get_representation(channelMask) + == AUDIO_CHANNEL_REPRESENTATION_POSITION + && DownmixerBufferProvider::isMultichannelCapable()) { DownmixerBufferProvider* pDbp = new DownmixerBufferProvider(channelMask, mMixerChannelMask, AUDIO_FORMAT_PCM_16_BIT /* TODO: use mMixerInFormat, now only PCM 16 */, @@ -2262,4 +2300,4 @@ AudioMixer::process_hook_t AudioMixer::getProcessHook(int processType, uint32_t } // ---------------------------------------------------------------------------- -}; // namespace android +} // namespace android diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h index 88e94c5..381036b 100644 --- a/services/audioflinger/AudioMixer.h +++ b/services/audioflinger/AudioMixer.h @@ -21,15 +21,15 @@ #include <stdint.h> #include <sys/types.h> +#include <hardware/audio_effect.h> +#include <media/AudioBufferProvider.h> +#include <media/nbaio/NBLog.h> +#include <system/audio.h> +#include <utils/Compat.h> #include <utils/threads.h> -#include <media/AudioBufferProvider.h> #include "AudioResampler.h" -#include <hardware/audio_effect.h> -#include <system/audio.h> -#include <media/nbaio/NBLog.h> - // FIXME This is actually unity gain, which might not be max in future, expressed in U.12 #define MAX_GAIN_INT AudioMixer::UNITY_GAIN_INT @@ -58,7 +58,7 @@ public: static const uint32_t MAX_NUM_CHANNELS_TO_DOWNMIX = AUDIO_CHANNEL_COUNT_MAX; static const uint16_t UNITY_GAIN_INT = 0x1000; - static const float UNITY_GAIN_FLOAT = 1.0f; + static const CONSTEXPR float UNITY_GAIN_FLOAT = 1.0f; enum { // names @@ -127,10 +127,16 @@ public: size_t getUnreleasedFrames(int name) const; static inline bool isValidPcmTrackFormat(audio_format_t format) { - return format == AUDIO_FORMAT_PCM_16_BIT || - format == AUDIO_FORMAT_PCM_24_BIT_PACKED || - format == AUDIO_FORMAT_PCM_32_BIT || - format == AUDIO_FORMAT_PCM_FLOAT; + switch (format) { + case AUDIO_FORMAT_PCM_8_BIT: + case AUDIO_FORMAT_PCM_16_BIT: + case AUDIO_FORMAT_PCM_24_BIT_PACKED: + case AUDIO_FORMAT_PCM_32_BIT: + case AUDIO_FORMAT_PCM_FLOAT: + return true; + default: + return false; + } } private: @@ -479,6 +485,6 @@ private: }; // ---------------------------------------------------------------------------- -}; // namespace android +} // namespace android #endif // ANDROID_AUDIO_MIXER_H diff --git a/services/audioflinger/AudioMixerOps.h b/services/audioflinger/AudioMixerOps.h index f7376a8..2678857 100644 --- a/services/audioflinger/AudioMixerOps.h +++ b/services/audioflinger/AudioMixerOps.h @@ -52,15 +52,12 @@ struct is_same<T, T> // partial specialization * * For high precision audio, only the <TO, TI, TV> = <float, float, float> * needs to be accelerated. This is perhaps the easiest form to do quickly as well. + * + * A generic version is NOT defined to catch any mistake of using it. */ template <typename TO, typename TI, typename TV> -inline TO MixMul(TI value, TV volume) { - COMPILE_TIME_ASSERT_FUNCTION_SCOPE(false); - // should not be here :-). - // To avoid mistakes, this template is always specialized. - return value * volume; -} +TO MixMul(TI value, TV volume); template <> inline int32_t MixMul<int32_t, int16_t, int16_t>(int16_t value, int16_t volume) { diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp index 1f7a613..46e3d6c 100644 --- a/services/audioflinger/AudioResampler.cpp +++ b/services/audioflinger/AudioResampler.cpp @@ -29,14 +29,11 @@ #include "AudioResamplerDyn.h" #ifdef __arm__ -#include <machine/cpu-features.h> + #define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1 #endif namespace android { -#ifdef __ARM_HAVE_HALFWORD_MULTIPLY // optimized asm option - #define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1 -#endif // __ARM_HAVE_HALFWORD_MULTIPLY // ---------------------------------------------------------------------------- class AudioResamplerOrder1 : public AudioResampler { diff --git a/services/audioflinger/AudioResampler.h b/services/audioflinger/AudioResampler.h index cdc6d92..863614a 100644 --- a/services/audioflinger/AudioResampler.h +++ b/services/audioflinger/AudioResampler.h @@ -19,7 +19,9 @@ #include <stdint.h> #include <sys/types.h> + #include <cutils/compiler.h> +#include <utils/Compat.h> #include <media/AudioBufferProvider.h> #include <system/audio.h> @@ -47,7 +49,7 @@ public: DYN_HIGH_QUALITY=7, }; - static const float UNITY_GAIN_FLOAT = 1.0f; + static const CONSTEXPR float UNITY_GAIN_FLOAT = 1.0f; static AudioResampler* create(audio_format_t format, int inChannelCount, int32_t sampleRate, src_quality quality=DEFAULT_QUALITY); @@ -168,7 +170,6 @@ private: }; // ---------------------------------------------------------------------------- -} -; // namespace android +} // namespace android #endif // ANDROID_AUDIO_RESAMPLER_H diff --git a/services/audioflinger/AudioResamplerCubic.cpp b/services/audioflinger/AudioResamplerCubic.cpp index 8f14ff9..d3cbd1c 100644 --- a/services/audioflinger/AudioResamplerCubic.cpp +++ b/services/audioflinger/AudioResamplerCubic.cpp @@ -185,5 +185,4 @@ save_state: } // ---------------------------------------------------------------------------- -} -; // namespace android +} // namespace android diff --git a/services/audioflinger/AudioResamplerCubic.h b/services/audioflinger/AudioResamplerCubic.h index b315da5..1ddc5f9 100644 --- a/services/audioflinger/AudioResamplerCubic.h +++ b/services/audioflinger/AudioResamplerCubic.h @@ -63,6 +63,6 @@ private: }; // ---------------------------------------------------------------------------- -}; // namespace android +} // namespace android #endif /*ANDROID_AUDIO_RESAMPLER_CUBIC_H*/ diff --git a/services/audioflinger/AudioResamplerDyn.cpp b/services/audioflinger/AudioResamplerDyn.cpp index 0eeb201..c21d4ca 100644 --- a/services/audioflinger/AudioResamplerDyn.cpp +++ b/services/audioflinger/AudioResamplerDyn.cpp @@ -618,4 +618,4 @@ template class AudioResamplerDyn<int16_t, int16_t, int32_t>; template class AudioResamplerDyn<int32_t, int16_t, int32_t>; // ---------------------------------------------------------------------------- -}; // namespace android +} // namespace android diff --git a/services/audioflinger/AudioResamplerDyn.h b/services/audioflinger/AudioResamplerDyn.h index e886a68..238b163 100644 --- a/services/audioflinger/AudioResamplerDyn.h +++ b/services/audioflinger/AudioResamplerDyn.h @@ -127,6 +127,6 @@ private: void* mCoefBuffer; // if a filter is created, this is not null }; -}; // namespace android +} // namespace android #endif /*ANDROID_AUDIO_RESAMPLER_DYN_H*/ diff --git a/services/audioflinger/AudioResamplerFirGen.h b/services/audioflinger/AudioResamplerFirGen.h index d024b2f..ad18965 100644 --- a/services/audioflinger/AudioResamplerFirGen.h +++ b/services/audioflinger/AudioResamplerFirGen.h @@ -17,6 +17,8 @@ #ifndef ANDROID_AUDIO_RESAMPLER_FIR_GEN_H #define ANDROID_AUDIO_RESAMPLER_FIR_GEN_H +#include "utils/Compat.h" + namespace android { /* @@ -187,22 +189,23 @@ static inline int64_t toint(double x, int64_t maxval) { template <int N> struct I0Term { - static const double value = I0Term<N-1>::value / (4. * N * N); + static const CONSTEXPR double value = I0Term<N-1>::value / (4. * N * N); }; template <> struct I0Term<0> { - static const double value = 1.; + static const CONSTEXPR double value = 1.; }; template <int N> struct I0ATerm { - static const double value = I0ATerm<N-1>::value * (2.*N-1.) * (2.*N-1.) / (8. * N); + static const CONSTEXPR double value = I0ATerm<N-1>::value * (2.*N-1.) * (2.*N-1.) / (8. * N); }; template <> struct I0ATerm<0> { // 1/sqrt(2*PI); - static const double value = 0.398942280401432677939946059934381868475858631164934657665925; + static const CONSTEXPR double value = + 0.398942280401432677939946059934381868475858631164934657665925; }; #if USE_HORNERS_METHOD @@ -704,6 +707,6 @@ static inline void firKaiserGen(T* coef, int L, int halfNumCoef, } } -}; // namespace android +} // namespace android #endif /*ANDROID_AUDIO_RESAMPLER_FIR_GEN_H*/ diff --git a/services/audioflinger/AudioResamplerFirOps.h b/services/audioflinger/AudioResamplerFirOps.h index bf2163f..658285d 100644 --- a/services/audioflinger/AudioResamplerFirOps.h +++ b/services/audioflinger/AudioResamplerFirOps.h @@ -25,7 +25,7 @@ namespace android { #define USE_INLINE_ASSEMBLY (false) #endif -#if USE_INLINE_ASSEMBLY && defined(__ARM_NEON__) +#if defined(__aarch64__) || defined(__ARM_NEON__) #define USE_NEON (true) #include <arm_neon.h> #else @@ -158,6 +158,6 @@ int32_t mulAddRL(int left, uint32_t inRL, int32_t v, int32_t a) #endif } -}; // namespace android +} // namespace android #endif /*ANDROID_AUDIO_RESAMPLER_FIR_OPS_H*/ diff --git a/services/audioflinger/AudioResamplerFirProcess.h b/services/audioflinger/AudioResamplerFirProcess.h index efc8055..176202e 100644 --- a/services/audioflinger/AudioResamplerFirProcess.h +++ b/services/audioflinger/AudioResamplerFirProcess.h @@ -174,7 +174,8 @@ struct InterpNull { * Process() calls ProcessBase() with TFUNC = InterpCompute, for interpolated phase. */ -template <int CHANNELS, int STRIDE, typename TFUNC, typename TC, typename TI, typename TO, typename TINTERP> +template <int CHANNELS, int STRIDE, typename TFUNC, typename TC, typename TI, typename TO, + typename TINTERP> static inline void ProcessBase(TO* const out, size_t count, @@ -242,6 +243,9 @@ void ProcessBase(TO* const out, } } +/* Calculates a single output frame from a polyphase resampling filter. + * See Process() for parameter details. + */ template <int CHANNELS, int STRIDE, typename TC, typename TI, typename TO> static inline void ProcessL(TO* const out, @@ -255,6 +259,39 @@ void ProcessL(TO* const out, ProcessBase<CHANNELS, STRIDE, InterpNull>(out, count, coefsP, coefsN, sP, sN, 0, volumeLR); } +/* + * Calculates a single output frame from a polyphase resampling filter, + * with filter phase interpolation. + * + * @param out should point to the output buffer with space for at least one output frame. + * + * @param count should be half the size of the total filter length (halfNumCoefs), as we + * use symmetry in filter coefficients to evaluate two dot products. + * + * @param coefsP is one phase of the polyphase filter bank of size halfNumCoefs, corresponding + * to the positive sP. + * + * @param coefsN is one phase of the polyphase filter bank of size halfNumCoefs, corresponding + * to the negative sN. + * + * @param coefsP1 is the next phase of coefsP (used for interpolation). + * + * @param coefsN1 is the next phase of coefsN (used for interpolation). + * + * @param sP is the positive half of the coefficients (as viewed by a convolution), + * starting at the original samples pointer and decrementing (by CHANNELS). + * + * @param sN is the negative half of the samples (as viewed by a convolution), + * starting at the original samples pointer + CHANNELS and incrementing (by CHANNELS). + * + * @param lerpP The fractional siting between the polyphase indices is given by the bits + * below coefShift. See fir() for details. + * + * @param volumeLR is a pointer to an array of two 32 bit volume values, one per stereo channel, + * expressed as a S32 integer or float. A negative value inverts the channel 180 degrees. + * The pointer volumeLR should be aligned to a minimum of 8 bytes. + * A typical value for volume is 0x1000 to align to a unity gain output of 20.12. + */ template <int CHANNELS, int STRIDE, typename TC, typename TI, typename TO, typename TINTERP> static inline void Process(TO* const out, @@ -268,11 +305,12 @@ void Process(TO* const out, TINTERP lerpP, const TO* const volumeLR) { - ProcessBase<CHANNELS, STRIDE, InterpCompute>(out, count, coefsP, coefsN, sP, sN, lerpP, volumeLR); + ProcessBase<CHANNELS, STRIDE, InterpCompute>(out, count, coefsP, coefsN, sP, sN, lerpP, + volumeLR); } /* - * Calculates a single output frame (two samples) from input sample pointer. + * Calculates a single output frame from input sample pointer. * * This sets up the params for the accelerated Process() and ProcessL() * functions to do the appropriate dot products. @@ -307,7 +345,7 @@ void Process(TO* const out, * the positive half of the filter is dot product from samples to samples-halfNumCoefs+1. * * @param volumeLR is a pointer to an array of two 32 bit volume values, one per stereo channel, - * expressed as a S32 integer. A negative value inverts the channel 180 degrees. + * expressed as a S32 integer or float. A negative value inverts the channel 180 degrees. * The pointer volumeLR should be aligned to a minimum of 8 bytes. * A typical value for volume is 0x1000 to align to a unity gain output of 20.12. * @@ -396,6 +434,6 @@ void fir(TO* const out, } } -}; // namespace android +} // namespace android #endif /*ANDROID_AUDIO_RESAMPLER_FIR_PROCESS_H*/ diff --git a/services/audioflinger/AudioResamplerFirProcessNeon.h b/services/audioflinger/AudioResamplerFirProcessNeon.h index f311cef..3de9edd 100644 --- a/services/audioflinger/AudioResamplerFirProcessNeon.h +++ b/services/audioflinger/AudioResamplerFirProcessNeon.h @@ -22,14 +22,35 @@ namespace android { // depends on AudioResamplerFirOps.h, AudioResamplerFirProcess.h #if USE_NEON + +// use intrinsics if inline arm32 assembly is not possible +#if !USE_INLINE_ASSEMBLY +#define USE_INTRINSIC +#endif + +// following intrinsics available only on ARM 64 bit ACLE +#ifndef __aarch64__ +#undef vld1q_f32_x2 +#undef vld1q_s32_x2 +#endif + +#define TO_STRING2(x) #x +#define TO_STRING(x) TO_STRING2(x) +// uncomment to print GCC version, may be relevant for intrinsic optimizations +/* #pragma message ("GCC version: " TO_STRING(__GNUC__) \ + "." TO_STRING(__GNUC_MINOR__) \ + "." TO_STRING(__GNUC_PATCHLEVEL__)) */ + // -// NEON specializations are enabled for Process() and ProcessL() +// NEON specializations are enabled for Process() and ProcessL() in AudioResamplerFirProcess.h +// +// Two variants are presented here: +// ARM NEON inline assembly which appears up to 10-15% faster than intrinsics (gcc 4.9) for arm32. +// ARM NEON intrinsics which can also be used by arm64 and x86/64 with NEON header. // -// TODO: Stride 16 and Stride 8 can be combined with one pass stride 8 (if necessary) -// and looping stride 16 (or vice versa). This has some polyphase coef data alignment -// issues with S16 coefs. Consider this later. // Macros to save a mono/stereo accumulator sample in q0 (and q4) as stereo out. +// These are only used for inline assembly. #define ASSEMBLY_ACCUMULATE_MONO \ "vld1.s32 {d2}, [%[vLR]:64] \n"/* (1) load volumes */\ "vld1.s32 {d3}, %[out] \n"/* (2) unaligned load the output */\ @@ -49,6 +70,458 @@ namespace android { "vqadd.s32 d3, d3, d0 \n"/* (1+4d) accumulate result (saturating)*/\ "vst1.s32 {d3}, %[out] \n"/* (2+2d)store result*/ +template <int CHANNELS, int STRIDE, bool FIXED> +static inline void ProcessNeonIntrinsic(int32_t* out, + int count, + const int16_t* coefsP, + const int16_t* coefsN, + const int16_t* sP, + const int16_t* sN, + const int32_t* volumeLR, + uint32_t lerpP, + const int16_t* coefsP1, + const int16_t* coefsN1) +{ + ALOG_ASSERT(count > 0 && (count & 7) == 0); // multiple of 8 + COMPILE_TIME_ASSERT_FUNCTION_SCOPE(CHANNELS == 1 || CHANNELS == 2); + + sP -= CHANNELS*((STRIDE>>1)-1); + coefsP = (const int16_t*)__builtin_assume_aligned(coefsP, 16); + coefsN = (const int16_t*)__builtin_assume_aligned(coefsN, 16); + + int16x4_t interp; + if (!FIXED) { + interp = vdup_n_s16(lerpP); + //interp = (int16x4_t)vset_lane_s32 ((int32x2_t)lerpP, interp, 0); + coefsP1 = (const int16_t*)__builtin_assume_aligned(coefsP1, 16); + coefsN1 = (const int16_t*)__builtin_assume_aligned(coefsN1, 16); + } + int32x4_t accum, accum2; + // warning uninitialized if we use veorq_s32 + // (alternative to below) accum = veorq_s32(accum, accum); + accum = vdupq_n_s32(0); + if (CHANNELS == 2) { + // (alternative to below) accum2 = veorq_s32(accum2, accum2); + accum2 = vdupq_n_s32(0); + } + do { + int16x8_t posCoef = vld1q_s16(coefsP); + coefsP += 8; + int16x8_t negCoef = vld1q_s16(coefsN); + coefsN += 8; + if (!FIXED) { // interpolate + int16x8_t posCoef1 = vld1q_s16(coefsP1); + coefsP1 += 8; + int16x8_t negCoef1 = vld1q_s16(coefsN1); + coefsN1 += 8; + + posCoef1 = vsubq_s16(posCoef1, posCoef); + negCoef = vsubq_s16(negCoef, negCoef1); + + posCoef1 = vqrdmulhq_lane_s16(posCoef1, interp, 0); + negCoef = vqrdmulhq_lane_s16(negCoef, interp, 0); + + posCoef = vaddq_s16(posCoef, posCoef1); + negCoef = vaddq_s16(negCoef, negCoef1); + } + switch (CHANNELS) { + case 1: { + int16x8_t posSamp = vld1q_s16(sP); + int16x8_t negSamp = vld1q_s16(sN); + sN += 8; + posSamp = vrev64q_s16(posSamp); + + // dot product + accum = vmlal_s16(accum, vget_low_s16(posSamp), vget_high_s16(posCoef)); // reversed + accum = vmlal_s16(accum, vget_high_s16(posSamp), vget_low_s16(posCoef)); // reversed + accum = vmlal_s16(accum, vget_low_s16(negSamp), vget_low_s16(negCoef)); + accum = vmlal_s16(accum, vget_high_s16(negSamp), vget_high_s16(negCoef)); + sP -= 8; + } break; + case 2: { + int16x8x2_t posSamp = vld2q_s16(sP); + int16x8x2_t negSamp = vld2q_s16(sN); + sN += 16; + posSamp.val[0] = vrev64q_s16(posSamp.val[0]); + posSamp.val[1] = vrev64q_s16(posSamp.val[1]); + + // dot product + accum = vmlal_s16(accum, vget_low_s16(posSamp.val[0]), vget_high_s16(posCoef)); // r + accum = vmlal_s16(accum, vget_high_s16(posSamp.val[0]), vget_low_s16(posCoef)); // r + accum2 = vmlal_s16(accum2, vget_low_s16(posSamp.val[1]), vget_high_s16(posCoef)); // r + accum2 = vmlal_s16(accum2, vget_high_s16(posSamp.val[1]), vget_low_s16(posCoef)); // r + accum = vmlal_s16(accum, vget_low_s16(negSamp.val[0]), vget_low_s16(negCoef)); + accum = vmlal_s16(accum, vget_high_s16(negSamp.val[0]), vget_high_s16(negCoef)); + accum2 = vmlal_s16(accum2, vget_low_s16(negSamp.val[1]), vget_low_s16(negCoef)); + accum2 = vmlal_s16(accum2, vget_high_s16(negSamp.val[1]), vget_high_s16(negCoef)); + sP -= 16; + } + } break; + } while (count -= 8); + + // multiply by volume and save + volumeLR = (const int32_t*)__builtin_assume_aligned(volumeLR, 8); + int32x2_t vLR = vld1_s32(volumeLR); + int32x2_t outSamp = vld1_s32(out); + // combine and funnel down accumulator + int32x2_t outAccum = vpadd_s32(vget_low_s32(accum), vget_high_s32(accum)); + if (CHANNELS == 1) { + // duplicate accum to both L and R + outAccum = vpadd_s32(outAccum, outAccum); + } else if (CHANNELS == 2) { + // accum2 contains R, fold in + int32x2_t outAccum2 = vpadd_s32(vget_low_s32(accum2), vget_high_s32(accum2)); + outAccum = vpadd_s32(outAccum, outAccum2); + } + outAccum = vqrdmulh_s32(outAccum, vLR); + outSamp = vqadd_s32(outSamp, outAccum); + vst1_s32(out, outSamp); +} + +template <int CHANNELS, int STRIDE, bool FIXED> +static inline void ProcessNeonIntrinsic(int32_t* out, + int count, + const int32_t* coefsP, + const int32_t* coefsN, + const int16_t* sP, + const int16_t* sN, + const int32_t* volumeLR, + uint32_t lerpP, + const int32_t* coefsP1, + const int32_t* coefsN1) +{ + ALOG_ASSERT(count > 0 && (count & 7) == 0); // multiple of 8 + COMPILE_TIME_ASSERT_FUNCTION_SCOPE(CHANNELS == 1 || CHANNELS == 2); + + sP -= CHANNELS*((STRIDE>>1)-1); + coefsP = (const int32_t*)__builtin_assume_aligned(coefsP, 16); + coefsN = (const int32_t*)__builtin_assume_aligned(coefsN, 16); + + int32x2_t interp; + if (!FIXED) { + interp = vdup_n_s32(lerpP); + coefsP1 = (const int32_t*)__builtin_assume_aligned(coefsP1, 16); + coefsN1 = (const int32_t*)__builtin_assume_aligned(coefsN1, 16); + } + int32x4_t accum, accum2; + // warning uninitialized if we use veorq_s32 + // (alternative to below) accum = veorq_s32(accum, accum); + accum = vdupq_n_s32(0); + if (CHANNELS == 2) { + // (alternative to below) accum2 = veorq_s32(accum2, accum2); + accum2 = vdupq_n_s32(0); + } + do { +#ifdef vld1q_s32_x2 + int32x4x2_t posCoef = vld1q_s32_x2(coefsP); + coefsP += 8; + int32x4x2_t negCoef = vld1q_s32_x2(coefsN); + coefsN += 8; +#else + int32x4x2_t posCoef; + posCoef.val[0] = vld1q_s32(coefsP); + coefsP += 4; + posCoef.val[1] = vld1q_s32(coefsP); + coefsP += 4; + int32x4x2_t negCoef; + negCoef.val[0] = vld1q_s32(coefsN); + coefsN += 4; + negCoef.val[1] = vld1q_s32(coefsN); + coefsN += 4; +#endif + if (!FIXED) { // interpolate +#ifdef vld1q_s32_x2 + int32x4x2_t posCoef1 = vld1q_s32_x2(coefsP1); + coefsP1 += 8; + int32x4x2_t negCoef1 = vld1q_s32_x2(coefsN1); + coefsN1 += 8; +#else + int32x4x2_t posCoef1; + posCoef1.val[0] = vld1q_s32(coefsP1); + coefsP1 += 4; + posCoef1.val[1] = vld1q_s32(coefsP1); + coefsP1 += 4; + int32x4x2_t negCoef1; + negCoef1.val[0] = vld1q_s32(coefsN1); + coefsN1 += 4; + negCoef1.val[1] = vld1q_s32(coefsN1); + coefsN1 += 4; +#endif + + posCoef1.val[0] = vsubq_s32(posCoef1.val[0], posCoef.val[0]); + posCoef1.val[1] = vsubq_s32(posCoef1.val[1], posCoef.val[1]); + negCoef.val[0] = vsubq_s32(negCoef.val[0], negCoef1.val[0]); + negCoef.val[1] = vsubq_s32(negCoef.val[1], negCoef1.val[1]); + + posCoef1.val[0] = vqrdmulhq_lane_s32(posCoef1.val[0], interp, 0); + posCoef1.val[1] = vqrdmulhq_lane_s32(posCoef1.val[1], interp, 0); + negCoef.val[0] = vqrdmulhq_lane_s32(negCoef.val[0], interp, 0); + negCoef.val[1] = vqrdmulhq_lane_s32(negCoef.val[1], interp, 0); + + posCoef.val[0] = vaddq_s32(posCoef.val[0], posCoef1.val[0]); + posCoef.val[1] = vaddq_s32(posCoef.val[1], posCoef1.val[1]); + negCoef.val[0] = vaddq_s32(negCoef.val[0], negCoef1.val[0]); + negCoef.val[1] = vaddq_s32(negCoef.val[1], negCoef1.val[1]); + } + switch (CHANNELS) { + case 1: { + int16x8_t posSamp = vld1q_s16(sP); + int16x8_t negSamp = vld1q_s16(sN); + sN += 8; + posSamp = vrev64q_s16(posSamp); + + int32x4_t posSamp0 = vshll_n_s16(vget_low_s16(posSamp), 15); + int32x4_t posSamp1 = vshll_n_s16(vget_high_s16(posSamp), 15); + int32x4_t negSamp0 = vshll_n_s16(vget_low_s16(negSamp), 15); + int32x4_t negSamp1 = vshll_n_s16(vget_high_s16(negSamp), 15); + + // dot product + posSamp0 = vqrdmulhq_s32(posSamp0, posCoef.val[1]); // reversed + posSamp1 = vqrdmulhq_s32(posSamp1, posCoef.val[0]); // reversed + negSamp0 = vqrdmulhq_s32(negSamp0, negCoef.val[0]); + negSamp1 = vqrdmulhq_s32(negSamp1, negCoef.val[1]); + + accum = vaddq_s32(accum, posSamp0); + negSamp0 = vaddq_s32(negSamp0, negSamp1); + accum = vaddq_s32(accum, posSamp1); + accum = vaddq_s32(accum, negSamp0); + + sP -= 8; + } break; + case 2: { + int16x8x2_t posSamp = vld2q_s16(sP); + int16x8x2_t negSamp = vld2q_s16(sN); + sN += 16; + posSamp.val[0] = vrev64q_s16(posSamp.val[0]); + posSamp.val[1] = vrev64q_s16(posSamp.val[1]); + + // left + int32x4_t posSamp0 = vshll_n_s16(vget_low_s16(posSamp.val[0]), 15); + int32x4_t posSamp1 = vshll_n_s16(vget_high_s16(posSamp.val[0]), 15); + int32x4_t negSamp0 = vshll_n_s16(vget_low_s16(negSamp.val[0]), 15); + int32x4_t negSamp1 = vshll_n_s16(vget_high_s16(negSamp.val[0]), 15); + + // dot product + posSamp0 = vqrdmulhq_s32(posSamp0, posCoef.val[1]); // reversed + posSamp1 = vqrdmulhq_s32(posSamp1, posCoef.val[0]); // reversed + negSamp0 = vqrdmulhq_s32(negSamp0, negCoef.val[0]); + negSamp1 = vqrdmulhq_s32(negSamp1, negCoef.val[1]); + + accum = vaddq_s32(accum, posSamp0); + negSamp0 = vaddq_s32(negSamp0, negSamp1); + accum = vaddq_s32(accum, posSamp1); + accum = vaddq_s32(accum, negSamp0); + + // right + posSamp0 = vshll_n_s16(vget_low_s16(posSamp.val[1]), 15); + posSamp1 = vshll_n_s16(vget_high_s16(posSamp.val[1]), 15); + negSamp0 = vshll_n_s16(vget_low_s16(negSamp.val[1]), 15); + negSamp1 = vshll_n_s16(vget_high_s16(negSamp.val[1]), 15); + + // dot product + posSamp0 = vqrdmulhq_s32(posSamp0, posCoef.val[1]); // reversed + posSamp1 = vqrdmulhq_s32(posSamp1, posCoef.val[0]); // reversed + negSamp0 = vqrdmulhq_s32(negSamp0, negCoef.val[0]); + negSamp1 = vqrdmulhq_s32(negSamp1, negCoef.val[1]); + + accum2 = vaddq_s32(accum2, posSamp0); + negSamp0 = vaddq_s32(negSamp0, negSamp1); + accum2 = vaddq_s32(accum2, posSamp1); + accum2 = vaddq_s32(accum2, negSamp0); + + sP -= 16; + } break; + } + } while (count -= 8); + + // multiply by volume and save + volumeLR = (const int32_t*)__builtin_assume_aligned(volumeLR, 8); + int32x2_t vLR = vld1_s32(volumeLR); + int32x2_t outSamp = vld1_s32(out); + // combine and funnel down accumulator + int32x2_t outAccum = vpadd_s32(vget_low_s32(accum), vget_high_s32(accum)); + if (CHANNELS == 1) { + // duplicate accum to both L and R + outAccum = vpadd_s32(outAccum, outAccum); + } else if (CHANNELS == 2) { + // accum2 contains R, fold in + int32x2_t outAccum2 = vpadd_s32(vget_low_s32(accum2), vget_high_s32(accum2)); + outAccum = vpadd_s32(outAccum, outAccum2); + } + outAccum = vqrdmulh_s32(outAccum, vLR); + outSamp = vqadd_s32(outSamp, outAccum); + vst1_s32(out, outSamp); +} + +template <int CHANNELS, int STRIDE, bool FIXED> +static inline void ProcessNeonIntrinsic(float* out, + int count, + const float* coefsP, + const float* coefsN, + const float* sP, + const float* sN, + const float* volumeLR, + float lerpP, + const float* coefsP1, + const float* coefsN1) +{ + ALOG_ASSERT(count > 0 && (count & 7) == 0); // multiple of 8 + COMPILE_TIME_ASSERT_FUNCTION_SCOPE(CHANNELS == 1 || CHANNELS == 2); + + sP -= CHANNELS*((STRIDE>>1)-1); + coefsP = (const float*)__builtin_assume_aligned(coefsP, 16); + coefsN = (const float*)__builtin_assume_aligned(coefsN, 16); + + float32x2_t interp; + if (!FIXED) { + interp = vdup_n_f32(lerpP); + coefsP1 = (const float*)__builtin_assume_aligned(coefsP1, 16); + coefsN1 = (const float*)__builtin_assume_aligned(coefsN1, 16); + } + float32x4_t accum, accum2; + // warning uninitialized if we use veorq_s32 + // (alternative to below) accum = veorq_s32(accum, accum); + accum = vdupq_n_f32(0); + if (CHANNELS == 2) { + // (alternative to below) accum2 = veorq_s32(accum2, accum2); + accum2 = vdupq_n_f32(0); + } + do { +#ifdef vld1q_f32_x2 + float32x4x2_t posCoef = vld1q_f32_x2(coefsP); + coefsP += 8; + float32x4x2_t negCoef = vld1q_f32_x2(coefsN); + coefsN += 8; +#else + float32x4x2_t posCoef; + posCoef.val[0] = vld1q_f32(coefsP); + coefsP += 4; + posCoef.val[1] = vld1q_f32(coefsP); + coefsP += 4; + float32x4x2_t negCoef; + negCoef.val[0] = vld1q_f32(coefsN); + coefsN += 4; + negCoef.val[1] = vld1q_f32(coefsN); + coefsN += 4; +#endif + if (!FIXED) { // interpolate +#ifdef vld1q_f32_x2 + float32x4x2_t posCoef1 = vld1q_f32_x2(coefsP1); + coefsP1 += 8; + float32x4x2_t negCoef1 = vld1q_f32_x2(coefsN1); + coefsN1 += 8; +#else + float32x4x2_t posCoef1; + posCoef1.val[0] = vld1q_f32(coefsP1); + coefsP1 += 4; + posCoef1.val[1] = vld1q_f32(coefsP1); + coefsP1 += 4; + float32x4x2_t negCoef1; + negCoef1.val[0] = vld1q_f32(coefsN1); + coefsN1 += 4; + negCoef1.val[1] = vld1q_f32(coefsN1); + coefsN1 += 4; +#endif + posCoef1.val[0] = vsubq_f32(posCoef1.val[0], posCoef.val[0]); + posCoef1.val[1] = vsubq_f32(posCoef1.val[1], posCoef.val[1]); + negCoef.val[0] = vsubq_f32(negCoef.val[0], negCoef1.val[0]); + negCoef.val[1] = vsubq_f32(negCoef.val[1], negCoef1.val[1]); + + posCoef.val[0] = vmlaq_lane_f32(posCoef.val[0], posCoef1.val[0], interp, 0); + posCoef.val[1] = vmlaq_lane_f32(posCoef.val[1], posCoef1.val[1], interp, 0); + negCoef.val[0] = vmlaq_lane_f32(negCoef1.val[0], negCoef.val[0], interp, 0); // rev + negCoef.val[1] = vmlaq_lane_f32(negCoef1.val[1], negCoef.val[1], interp, 0); // rev + } + switch (CHANNELS) { + case 1: { +#ifdef vld1q_f32_x2 + float32x4x2_t posSamp = vld1q_f32_x2(sP); + float32x4x2_t negSamp = vld1q_f32_x2(sN); + sN += 8; + sP -= 8; +#else + float32x4x2_t posSamp; + posSamp.val[0] = vld1q_f32(sP); + sP += 4; + posSamp.val[1] = vld1q_f32(sP); + sP -= 12; + float32x4x2_t negSamp; + negSamp.val[0] = vld1q_f32(sN); + sN += 4; + negSamp.val[1] = vld1q_f32(sN); + sN += 4; +#endif + // effectively we want a vrev128q_f32() + posSamp.val[0] = vrev64q_f32(posSamp.val[0]); + posSamp.val[1] = vrev64q_f32(posSamp.val[1]); + posSamp.val[0] = vcombine_f32( + vget_high_f32(posSamp.val[0]), vget_low_f32(posSamp.val[0])); + posSamp.val[1] = vcombine_f32( + vget_high_f32(posSamp.val[1]), vget_low_f32(posSamp.val[1])); + + accum = vmlaq_f32(accum, posSamp.val[0], posCoef.val[1]); + accum = vmlaq_f32(accum, posSamp.val[1], posCoef.val[0]); + accum = vmlaq_f32(accum, negSamp.val[0], negCoef.val[0]); + accum = vmlaq_f32(accum, negSamp.val[1], negCoef.val[1]); + } break; + case 2: { + float32x4x2_t posSamp0 = vld2q_f32(sP); + sP += 8; + float32x4x2_t negSamp0 = vld2q_f32(sN); + sN += 8; + posSamp0.val[0] = vrev64q_f32(posSamp0.val[0]); + posSamp0.val[1] = vrev64q_f32(posSamp0.val[1]); + posSamp0.val[0] = vcombine_f32( + vget_high_f32(posSamp0.val[0]), vget_low_f32(posSamp0.val[0])); + posSamp0.val[1] = vcombine_f32( + vget_high_f32(posSamp0.val[1]), vget_low_f32(posSamp0.val[1])); + + float32x4x2_t posSamp1 = vld2q_f32(sP); + sP -= 24; + float32x4x2_t negSamp1 = vld2q_f32(sN); + sN += 8; + posSamp1.val[0] = vrev64q_f32(posSamp1.val[0]); + posSamp1.val[1] = vrev64q_f32(posSamp1.val[1]); + posSamp1.val[0] = vcombine_f32( + vget_high_f32(posSamp1.val[0]), vget_low_f32(posSamp1.val[0])); + posSamp1.val[1] = vcombine_f32( + vget_high_f32(posSamp1.val[1]), vget_low_f32(posSamp1.val[1])); + + // Note: speed is affected by accumulation order. + // Also, speed appears slower using vmul/vadd instead of vmla for + // stereo case, comparable for mono. + + accum = vmlaq_f32(accum, negSamp0.val[0], negCoef.val[0]); + accum = vmlaq_f32(accum, negSamp1.val[0], negCoef.val[1]); + accum2 = vmlaq_f32(accum2, negSamp0.val[1], negCoef.val[0]); + accum2 = vmlaq_f32(accum2, negSamp1.val[1], negCoef.val[1]); + + accum = vmlaq_f32(accum, posSamp0.val[0], posCoef.val[1]); // reversed + accum = vmlaq_f32(accum, posSamp1.val[0], posCoef.val[0]); // reversed + accum2 = vmlaq_f32(accum2, posSamp0.val[1], posCoef.val[1]); // reversed + accum2 = vmlaq_f32(accum2, posSamp1.val[1], posCoef.val[0]); // reversed + } break; + } + } while (count -= 8); + + // multiply by volume and save + volumeLR = (const float*)__builtin_assume_aligned(volumeLR, 8); + float32x2_t vLR = vld1_f32(volumeLR); + float32x2_t outSamp = vld1_f32(out); + // combine and funnel down accumulator + float32x2_t outAccum = vpadd_f32(vget_low_f32(accum), vget_high_f32(accum)); + if (CHANNELS == 1) { + // duplicate accum to both L and R + outAccum = vpadd_f32(outAccum, outAccum); + } else if (CHANNELS == 2) { + // accum2 contains R, fold in + float32x2_t outAccum2 = vpadd_f32(vget_low_f32(accum2), vget_high_f32(accum2)); + outAccum = vpadd_f32(outAccum, outAccum2); + } + outSamp = vmla_f32(outSamp, outAccum, vLR); + vst1_f32(out, outSamp); +} + template <> inline void ProcessL<1, 16>(int32_t* const out, int count, @@ -58,6 +531,10 @@ inline void ProcessL<1, 16>(int32_t* const out, const int16_t* sN, const int32_t* const volumeLR) { +#ifdef USE_INTRINSIC + ProcessNeonIntrinsic<1, 16, true>(out, count, coefsP, coefsN, sP, sN, volumeLR, + 0 /*lerpP*/, NULL /*coefsP1*/, NULL /*coefsN1*/); +#else const int CHANNELS = 1; // template specialization does not preserve params const int STRIDE = 16; sP -= CHANNELS*((STRIDE>>1)-1); @@ -99,6 +576,7 @@ inline void ProcessL<1, 16>(int32_t* const out, "q0", "q1", "q2", "q3", "q8", "q10" ); +#endif } template <> @@ -110,6 +588,10 @@ inline void ProcessL<2, 16>(int32_t* const out, const int16_t* sN, const int32_t* const volumeLR) { +#ifdef USE_INTRINSIC + ProcessNeonIntrinsic<2, 16, true>(out, count, coefsP, coefsN, sP, sN, volumeLR, + 0 /*lerpP*/, NULL /*coefsP1*/, NULL /*coefsN1*/); +#else const int CHANNELS = 2; // template specialization does not preserve params const int STRIDE = 16; sP -= CHANNELS*((STRIDE>>1)-1); @@ -119,13 +601,13 @@ inline void ProcessL<2, 16>(int32_t* const out, "1: \n" - "vld2.16 {q2, q3}, [%[sP]] \n"// (3+0d) load 8 16-bits stereo samples - "vld2.16 {q5, q6}, [%[sN]]! \n"// (3) load 8 16-bits stereo samples + "vld2.16 {q2, q3}, [%[sP]] \n"// (3+0d) load 8 16-bits stereo frames + "vld2.16 {q5, q6}, [%[sN]]! \n"// (3) load 8 16-bits stereo frames "vld1.16 {q8}, [%[coefsP0]:128]! \n"// (1) load 8 16-bits coefs "vld1.16 {q10}, [%[coefsN0]:128]! \n"// (1) load 8 16-bits coefs - "vrev64.16 q2, q2 \n"// (1) reverse 8 frames of the left positive - "vrev64.16 q3, q3 \n"// (0 combines+) reverse right positive + "vrev64.16 q2, q2 \n"// (1) reverse 8 samples of positive left + "vrev64.16 q3, q3 \n"// (0 combines+) reverse positive right "vmlal.s16 q0, d4, d17 \n"// (1) multiply (reversed) samples left "vmlal.s16 q0, d5, d16 \n"// (1) multiply (reversed) samples left @@ -157,6 +639,7 @@ inline void ProcessL<2, 16>(int32_t* const out, "q4", "q5", "q6", "q8", "q10" ); +#endif } template <> @@ -171,6 +654,11 @@ inline void Process<1, 16>(int32_t* const out, uint32_t lerpP, const int32_t* const volumeLR) { +#ifdef USE_INTRINSIC + ProcessNeonIntrinsic<1, 16, false>(out, count, coefsP, coefsN, sP, sN, volumeLR, + lerpP, coefsP1, coefsN1); +#else + const int CHANNELS = 1; // template specialization does not preserve params const int STRIDE = 16; sP -= CHANNELS*((STRIDE>>1)-1); @@ -227,6 +715,7 @@ inline void Process<1, 16>(int32_t* const out, "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11" ); +#endif } template <> @@ -241,6 +730,10 @@ inline void Process<2, 16>(int32_t* const out, uint32_t lerpP, const int32_t* const volumeLR) { +#ifdef USE_INTRINSIC + ProcessNeonIntrinsic<2, 16, false>(out, count, coefsP, coefsN, sP, sN, volumeLR, + lerpP, coefsP1, coefsN1); +#else const int CHANNELS = 2; // template specialization does not preserve params const int STRIDE = 16; sP -= CHANNELS*((STRIDE>>1)-1); @@ -251,8 +744,8 @@ inline void Process<2, 16>(int32_t* const out, "1: \n" - "vld2.16 {q2, q3}, [%[sP]] \n"// (3+0d) load 8 16-bits stereo samples - "vld2.16 {q5, q6}, [%[sN]]! \n"// (3) load 8 16-bits stereo samples + "vld2.16 {q2, q3}, [%[sP]] \n"// (3+0d) load 8 16-bits stereo frames + "vld2.16 {q5, q6}, [%[sN]]! \n"// (3) load 8 16-bits stereo frames "vld1.16 {q8}, [%[coefsP0]:128]! \n"// (1) load 8 16-bits coefs "vld1.16 {q9}, [%[coefsP1]:128]! \n"// (1) load 8 16-bits coefs for interpolation "vld1.16 {q10}, [%[coefsN1]:128]! \n"// (1) load 8 16-bits coefs @@ -264,8 +757,8 @@ inline void Process<2, 16>(int32_t* const out, "vqrdmulh.s16 q9, q9, d2[0] \n"// (2) interpolate (step2) 1st set of coefs "vqrdmulh.s16 q11, q11, d2[0] \n"// (2) interpolate (step2) 2nd set of coefs - "vrev64.16 q2, q2 \n"// (1) reverse 8 frames of the left positive - "vrev64.16 q3, q3 \n"// (1) reverse 8 frames of the right positive + "vrev64.16 q2, q2 \n"// (1) reverse 8 samples of positive left + "vrev64.16 q3, q3 \n"// (1) reverse 8 samples of positive right "vadd.s16 q8, q8, q9 \n"// (1+1d) interpolate (step3) 1st set "vadd.s16 q10, q10, q11 \n"// (1+1d) interpolate (step3) 2nd set @@ -303,6 +796,7 @@ inline void Process<2, 16>(int32_t* const out, "q4", "q5", "q6", "q8", "q9", "q10", "q11" ); +#endif } template <> @@ -314,6 +808,10 @@ inline void ProcessL<1, 16>(int32_t* const out, const int16_t* sN, const int32_t* const volumeLR) { +#ifdef USE_INTRINSIC + ProcessNeonIntrinsic<1, 16, true>(out, count, coefsP, coefsN, sP, sN, volumeLR, + 0 /*lerpP*/, NULL /*coefsP1*/, NULL /*coefsN1*/); +#else const int CHANNELS = 1; // template specialization does not preserve params const int STRIDE = 16; sP -= CHANNELS*((STRIDE>>1)-1); @@ -327,7 +825,7 @@ inline void ProcessL<1, 16>(int32_t* const out, "vld1.32 {q8, q9}, [%[coefsP0]:128]! \n"// load 8 32-bits coefs "vld1.32 {q10, q11}, [%[coefsN0]:128]! \n"// load 8 32-bits coefs - "vrev64.16 q2, q2 \n"// reverse 8 frames of the positive side + "vrev64.16 q2, q2 \n"// reverse 8 samples of the positive side "vshll.s16 q12, d4, #15 \n"// extend samples to 31 bits "vshll.s16 q13, d5, #15 \n"// extend samples to 31 bits @@ -335,10 +833,10 @@ inline void ProcessL<1, 16>(int32_t* const out, "vshll.s16 q14, d6, #15 \n"// extend samples to 31 bits "vshll.s16 q15, d7, #15 \n"// extend samples to 31 bits - "vqrdmulh.s32 q12, q12, q9 \n"// multiply samples by interpolated coef - "vqrdmulh.s32 q13, q13, q8 \n"// multiply samples by interpolated coef - "vqrdmulh.s32 q14, q14, q10 \n"// multiply samples by interpolated coef - "vqrdmulh.s32 q15, q15, q11 \n"// multiply samples by interpolated coef + "vqrdmulh.s32 q12, q12, q9 \n"// multiply samples + "vqrdmulh.s32 q13, q13, q8 \n"// multiply samples + "vqrdmulh.s32 q14, q14, q10 \n"// multiply samples + "vqrdmulh.s32 q15, q15, q11 \n"// multiply samples "vadd.s32 q0, q0, q12 \n"// accumulate result "vadd.s32 q13, q13, q14 \n"// accumulate result @@ -364,6 +862,7 @@ inline void ProcessL<1, 16>(int32_t* const out, "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" ); +#endif } template <> @@ -375,6 +874,10 @@ inline void ProcessL<2, 16>(int32_t* const out, const int16_t* sN, const int32_t* const volumeLR) { +#ifdef USE_INTRINSIC + ProcessNeonIntrinsic<2, 16, true>(out, count, coefsP, coefsN, sP, sN, volumeLR, + 0 /*lerpP*/, NULL /*coefsP1*/, NULL /*coefsN1*/); +#else const int CHANNELS = 2; // template specialization does not preserve params const int STRIDE = 16; sP -= CHANNELS*((STRIDE>>1)-1); @@ -384,13 +887,13 @@ inline void ProcessL<2, 16>(int32_t* const out, "1: \n" - "vld2.16 {q2, q3}, [%[sP]] \n"// load 4 16-bits stereo samples - "vld2.16 {q5, q6}, [%[sN]]! \n"// load 4 16-bits stereo samples - "vld1.32 {q8, q9}, [%[coefsP0]:128]! \n"// load 4 32-bits coefs - "vld1.32 {q10, q11}, [%[coefsN0]:128]! \n"// load 4 32-bits coefs + "vld2.16 {q2, q3}, [%[sP]] \n"// load 8 16-bits stereo frames + "vld2.16 {q5, q6}, [%[sN]]! \n"// load 8 16-bits stereo frames + "vld1.32 {q8, q9}, [%[coefsP0]:128]! \n"// load 8 32-bits coefs + "vld1.32 {q10, q11}, [%[coefsN0]:128]! \n"// load 8 32-bits coefs - "vrev64.16 q2, q2 \n"// reverse 8 frames of the positive side - "vrev64.16 q3, q3 \n"// reverse 8 frames of the positive side + "vrev64.16 q2, q2 \n"// reverse 8 samples of positive left + "vrev64.16 q3, q3 \n"// reverse 8 samples of positive right "vshll.s16 q12, d4, #15 \n"// extend samples to 31 bits "vshll.s16 q13, d5, #15 \n"// extend samples to 31 bits @@ -398,15 +901,15 @@ inline void ProcessL<2, 16>(int32_t* const out, "vshll.s16 q14, d10, #15 \n"// extend samples to 31 bits "vshll.s16 q15, d11, #15 \n"// extend samples to 31 bits - "vqrdmulh.s32 q12, q12, q9 \n"// multiply samples by interpolated coef - "vqrdmulh.s32 q13, q13, q8 \n"// multiply samples by interpolated coef - "vqrdmulh.s32 q14, q14, q10 \n"// multiply samples by interpolated coef - "vqrdmulh.s32 q15, q15, q11 \n"// multiply samples by interpolated coef + "vqrdmulh.s32 q12, q12, q9 \n"// multiply samples by coef + "vqrdmulh.s32 q13, q13, q8 \n"// multiply samples by coef + "vqrdmulh.s32 q14, q14, q10 \n"// multiply samples by coef + "vqrdmulh.s32 q15, q15, q11 \n"// multiply samples by coef "vadd.s32 q0, q0, q12 \n"// accumulate result "vadd.s32 q13, q13, q14 \n"// accumulate result - "vadd.s32 q0, q0, q15 \n"// (+1) accumulate result - "vadd.s32 q0, q0, q13 \n"// (+1) accumulate result + "vadd.s32 q0, q0, q15 \n"// accumulate result + "vadd.s32 q0, q0, q13 \n"// accumulate result "vshll.s16 q12, d6, #15 \n"// extend samples to 31 bits "vshll.s16 q13, d7, #15 \n"// extend samples to 31 bits @@ -414,15 +917,15 @@ inline void ProcessL<2, 16>(int32_t* const out, "vshll.s16 q14, d12, #15 \n"// extend samples to 31 bits "vshll.s16 q15, d13, #15 \n"// extend samples to 31 bits - "vqrdmulh.s32 q12, q12, q9 \n"// multiply samples by interpolated coef - "vqrdmulh.s32 q13, q13, q8 \n"// multiply samples by interpolated coef - "vqrdmulh.s32 q14, q14, q10 \n"// multiply samples by interpolated coef - "vqrdmulh.s32 q15, q15, q11 \n"// multiply samples by interpolated coef + "vqrdmulh.s32 q12, q12, q9 \n"// multiply samples by coef + "vqrdmulh.s32 q13, q13, q8 \n"// multiply samples by coef + "vqrdmulh.s32 q14, q14, q10 \n"// multiply samples by coef + "vqrdmulh.s32 q15, q15, q11 \n"// multiply samples by coef "vadd.s32 q4, q4, q12 \n"// accumulate result "vadd.s32 q13, q13, q14 \n"// accumulate result - "vadd.s32 q4, q4, q15 \n"// (+1) accumulate result - "vadd.s32 q4, q4, q13 \n"// (+1) accumulate result + "vadd.s32 q4, q4, q15 \n"// accumulate result + "vadd.s32 q4, q4, q13 \n"// accumulate result "subs %[count], %[count], #8 \n"// update loop counter "sub %[sP], %[sP], #32 \n"// move pointer to next set of samples @@ -444,6 +947,7 @@ inline void ProcessL<2, 16>(int32_t* const out, "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" ); +#endif } template <> @@ -458,6 +962,10 @@ inline void Process<1, 16>(int32_t* const out, uint32_t lerpP, const int32_t* const volumeLR) { +#ifdef USE_INTRINSIC + ProcessNeonIntrinsic<1, 16, false>(out, count, coefsP, coefsN, sP, sN, volumeLR, + lerpP, coefsP1, coefsN1); +#else const int CHANNELS = 1; // template specialization does not preserve params const int STRIDE = 16; sP -= CHANNELS*((STRIDE>>1)-1); @@ -489,7 +997,7 @@ inline void Process<1, 16>(int32_t* const out, "vadd.s32 q10, q10, q14 \n"// interpolate (step3) "vadd.s32 q11, q11, q15 \n"// interpolate (step3) - "vrev64.16 q2, q2 \n"// reverse 8 frames of the positive side + "vrev64.16 q2, q2 \n"// reverse 8 samples of the positive side "vshll.s16 q12, d4, #15 \n"// extend samples to 31 bits "vshll.s16 q13, d5, #15 \n"// extend samples to 31 bits @@ -529,6 +1037,7 @@ inline void Process<1, 16>(int32_t* const out, "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" ); +#endif } template <> @@ -543,6 +1052,10 @@ inline void Process<2, 16>(int32_t* const out, uint32_t lerpP, const int32_t* const volumeLR) { +#ifdef USE_INTRINSIC + ProcessNeonIntrinsic<2, 16, false>(out, count, coefsP, coefsN, sP, sN, volumeLR, + lerpP, coefsP1, coefsN1); +#else const int CHANNELS = 2; // template specialization does not preserve params const int STRIDE = 16; sP -= CHANNELS*((STRIDE>>1)-1); @@ -553,8 +1066,8 @@ inline void Process<2, 16>(int32_t* const out, "1: \n" - "vld2.16 {q2, q3}, [%[sP]] \n"// load 4 16-bits stereo samples - "vld2.16 {q5, q6}, [%[sN]]! \n"// load 4 16-bits stereo samples + "vld2.16 {q2, q3}, [%[sP]] \n"// load 8 16-bits stereo frames + "vld2.16 {q5, q6}, [%[sN]]! \n"// load 8 16-bits stereo frames "vld1.32 {q8, q9}, [%[coefsP0]:128]! \n"// load 8 32-bits coefs "vld1.32 {q12, q13}, [%[coefsP1]:128]! \n"// load 8 32-bits coefs "vld1.32 {q10, q11}, [%[coefsN1]:128]! \n"// load 8 32-bits coefs @@ -575,8 +1088,8 @@ inline void Process<2, 16>(int32_t* const out, "vadd.s32 q10, q10, q14 \n"// interpolate (step3) "vadd.s32 q11, q11, q15 \n"// interpolate (step3) - "vrev64.16 q2, q2 \n"// reverse 8 frames of the positive side - "vrev64.16 q3, q3 \n"// reverse 8 frames of the positive side + "vrev64.16 q2, q2 \n"// reverse 8 samples of positive left + "vrev64.16 q3, q3 \n"// reverse 8 samples of positive right "vshll.s16 q12, d4, #15 \n"// extend samples to 31 bits "vshll.s16 q13, d5, #15 \n"// extend samples to 31 bits @@ -591,8 +1104,8 @@ inline void Process<2, 16>(int32_t* const out, "vadd.s32 q0, q0, q12 \n"// accumulate result "vadd.s32 q13, q13, q14 \n"// accumulate result - "vadd.s32 q0, q0, q15 \n"// (+1) accumulate result - "vadd.s32 q0, q0, q13 \n"// (+1) accumulate result + "vadd.s32 q0, q0, q15 \n"// accumulate result + "vadd.s32 q0, q0, q13 \n"// accumulate result "vshll.s16 q12, d6, #15 \n"// extend samples to 31 bits "vshll.s16 q13, d7, #15 \n"// extend samples to 31 bits @@ -607,8 +1120,8 @@ inline void Process<2, 16>(int32_t* const out, "vadd.s32 q4, q4, q12 \n"// accumulate result "vadd.s32 q13, q13, q14 \n"// accumulate result - "vadd.s32 q4, q4, q15 \n"// (+1) accumulate result - "vadd.s32 q4, q4, q13 \n"// (+1) accumulate result + "vadd.s32 q4, q4, q15 \n"// accumulate result + "vadd.s32 q4, q4, q13 \n"// accumulate result "subs %[count], %[count], #8 \n"// update loop counter "sub %[sP], %[sP], #32 \n"// move pointer to next set of samples @@ -633,517 +1146,69 @@ inline void Process<2, 16>(int32_t* const out, "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" ); +#endif } -template <> -inline void ProcessL<1, 8>(int32_t* const out, +template<> +inline void ProcessL<1, 16>(float* const out, int count, - const int16_t* coefsP, - const int16_t* coefsN, - const int16_t* sP, - const int16_t* sN, - const int32_t* const volumeLR) + const float* coefsP, + const float* coefsN, + const float* sP, + const float* sN, + const float* const volumeLR) { - const int CHANNELS = 1; // template specialization does not preserve params - const int STRIDE = 8; - sP -= CHANNELS*((STRIDE>>1)-1); - asm ( - "veor q0, q0, q0 \n"// (0 - combines+) accumulator = 0 - - "1: \n" - - "vld1.16 {d4}, [%[sP]] \n"// (2+0d) load 4 16-bits mono samples - "vld1.16 {d6}, [%[sN]]! \n"// (2) load 4 16-bits mono samples - "vld1.16 {d16}, [%[coefsP0]:64]! \n"// (1) load 4 16-bits coefs - "vld1.16 {d20}, [%[coefsN0]:64]! \n"// (1) load 4 16-bits coefs - - "vrev64.16 d4, d4 \n"// (1) reversed s3, s2, s1, s0, s7, s6, s5, s4 - - // reordering the vmal to do d6, d7 before d4, d5 is slower(?) - "vmlal.s16 q0, d4, d16 \n"// (1) multiply (reversed)samples by coef - "vmlal.s16 q0, d6, d20 \n"// (1) multiply neg samples - - // moving these ARM instructions before neon above seems to be slower - "subs %[count], %[count], #4 \n"// (1) update loop counter - "sub %[sP], %[sP], #8 \n"// (0) move pointer to next set of samples - - // sP used after branch (warning) - "bne 1b \n"// loop - - ASSEMBLY_ACCUMULATE_MONO - - : [out] "=Uv" (out[0]), - [count] "+r" (count), - [coefsP0] "+r" (coefsP), - [coefsN0] "+r" (coefsN), - [sP] "+r" (sP), - [sN] "+r" (sN) - : [vLR] "r" (volumeLR) - : "cc", "memory", - "q0", "q1", "q2", "q3", - "q8", "q10" - ); + ProcessNeonIntrinsic<1, 16, true>(out, count, coefsP, coefsN, sP, sN, volumeLR, + 0 /*lerpP*/, NULL /*coefsP1*/, NULL /*coefsN1*/); } -template <> -inline void ProcessL<2, 8>(int32_t* const out, +template<> +inline void ProcessL<2, 16>(float* const out, int count, - const int16_t* coefsP, - const int16_t* coefsN, - const int16_t* sP, - const int16_t* sN, - const int32_t* const volumeLR) + const float* coefsP, + const float* coefsN, + const float* sP, + const float* sN, + const float* const volumeLR) { - const int CHANNELS = 2; // template specialization does not preserve params - const int STRIDE = 8; - sP -= CHANNELS*((STRIDE>>1)-1); - asm ( - "veor q0, q0, q0 \n"// (1) acc_L = 0 - "veor q4, q4, q4 \n"// (0 combines+) acc_R = 0 - - "1: \n" - - "vld2.16 {d4, d5}, [%[sP]] \n"// (2+0d) load 8 16-bits stereo samples - "vld2.16 {d6, d7}, [%[sN]]! \n"// (2) load 8 16-bits stereo samples - "vld1.16 {d16}, [%[coefsP0]:64]! \n"// (1) load 8 16-bits coefs - "vld1.16 {d20}, [%[coefsN0]:64]! \n"// (1) load 8 16-bits coefs - - "vrev64.16 q2, q2 \n"// (1) reverse 8 frames of the left positive - - "vmlal.s16 q0, d4, d16 \n"// (1) multiply (reversed) samples left - "vmlal.s16 q4, d5, d16 \n"// (1) multiply (reversed) samples right - "vmlal.s16 q0, d6, d20 \n"// (1) multiply samples left - "vmlal.s16 q4, d7, d20 \n"// (1) multiply samples right - - // moving these ARM before neon seems to be slower - "subs %[count], %[count], #4 \n"// (1) update loop counter - "sub %[sP], %[sP], #16 \n"// (0) move pointer to next set of samples - - // sP used after branch (warning) - "bne 1b \n"// loop - - ASSEMBLY_ACCUMULATE_STEREO - - : [out] "=Uv" (out[0]), - [count] "+r" (count), - [coefsP0] "+r" (coefsP), - [coefsN0] "+r" (coefsN), - [sP] "+r" (sP), - [sN] "+r" (sN) - : [vLR] "r" (volumeLR) - : "cc", "memory", - "q0", "q1", "q2", "q3", - "q4", "q5", "q6", - "q8", "q10" - ); + ProcessNeonIntrinsic<2, 16, true>(out, count, coefsP, coefsN, sP, sN, volumeLR, + 0 /*lerpP*/, NULL /*coefsP1*/, NULL /*coefsN1*/); } -template <> -inline void Process<1, 8>(int32_t* const out, +template<> +inline void Process<1, 16>(float* const out, int count, - const int16_t* coefsP, - const int16_t* coefsN, - const int16_t* coefsP1, - const int16_t* coefsN1, - const int16_t* sP, - const int16_t* sN, - uint32_t lerpP, - const int32_t* const volumeLR) + const float* coefsP, + const float* coefsN, + const float* coefsP1, + const float* coefsN1, + const float* sP, + const float* sN, + float lerpP, + const float* const volumeLR) { - const int CHANNELS = 1; // template specialization does not preserve params - const int STRIDE = 8; - sP -= CHANNELS*((STRIDE>>1)-1); - asm ( - "vmov.32 d2[0], %[lerpP] \n"// load the positive phase S32 Q15 - "veor q0, q0, q0 \n"// (0 - combines+) accumulator = 0 - - "1: \n" - - "vld1.16 {d4}, [%[sP]] \n"// (2+0d) load 4 16-bits mono samples - "vld1.16 {d6}, [%[sN]]! \n"// (2) load 4 16-bits mono samples - "vld1.16 {d16}, [%[coefsP0]:64]! \n"// (1) load 4 16-bits coefs - "vld1.16 {d17}, [%[coefsP1]:64]! \n"// (1) load 4 16-bits coefs for interpolation - "vld1.16 {d20}, [%[coefsN1]:64]! \n"// (1) load 4 16-bits coefs - "vld1.16 {d21}, [%[coefsN0]:64]! \n"// (1) load 4 16-bits coefs for interpolation - - "vsub.s16 d17, d17, d16 \n"// (1) interpolate (step1) 1st set of coefs - "vsub.s16 d21, d21, d20 \n"// (1) interpolate (step1) 2nd set of coets - - "vqrdmulh.s16 d17, d17, d2[0] \n"// (2) interpolate (step2) 1st set of coefs - "vqrdmulh.s16 d21, d21, d2[0] \n"// (2) interpolate (step2) 2nd set of coefs - - "vrev64.16 d4, d4 \n"// (1) reverse s3, s2, s1, s0, s7, s6, s5, s4 - - "vadd.s16 d16, d16, d17 \n"// (1+2d) interpolate (step3) 1st set - "vadd.s16 d20, d20, d21 \n"// (1+1d) interpolate (step3) 2nd set - - // reordering the vmal to do d6, d7 before d4, d5 is slower(?) - "vmlal.s16 q0, d4, d16 \n"// (1+0d) multiply (reversed)by coef - "vmlal.s16 q0, d6, d20 \n"// (1) multiply neg samples - - // moving these ARM instructions before neon above seems to be slower - "subs %[count], %[count], #4 \n"// (1) update loop counter - "sub %[sP], %[sP], #8 \n"// move pointer to next set of samples - - // sP used after branch (warning) - "bne 1b \n"// loop - - ASSEMBLY_ACCUMULATE_MONO - - : [out] "=Uv" (out[0]), - [count] "+r" (count), - [coefsP0] "+r" (coefsP), - [coefsN0] "+r" (coefsN), - [coefsP1] "+r" (coefsP1), - [coefsN1] "+r" (coefsN1), - [sP] "+r" (sP), - [sN] "+r" (sN) - : [lerpP] "r" (lerpP), - [vLR] "r" (volumeLR) - : "cc", "memory", - "q0", "q1", "q2", "q3", - "q8", "q9", "q10", "q11" - ); + ProcessNeonIntrinsic<1, 16, false>(out, count, coefsP, coefsN, sP, sN, volumeLR, + lerpP, coefsP1, coefsN1); } -template <> -inline void Process<2, 8>(int32_t* const out, +template<> +inline void Process<2, 16>(float* const out, int count, - const int16_t* coefsP, - const int16_t* coefsN, - const int16_t* coefsP1, - const int16_t* coefsN1, - const int16_t* sP, - const int16_t* sN, - uint32_t lerpP, - const int32_t* const volumeLR) + const float* coefsP, + const float* coefsN, + const float* coefsP1, + const float* coefsN1, + const float* sP, + const float* sN, + float lerpP, + const float* const volumeLR) { - const int CHANNELS = 2; // template specialization does not preserve params - const int STRIDE = 8; - sP -= CHANNELS*((STRIDE>>1)-1); - asm ( - "vmov.32 d2[0], %[lerpP] \n"// load the positive phase - "veor q0, q0, q0 \n"// (1) acc_L = 0 - "veor q4, q4, q4 \n"// (0 combines+) acc_R = 0 - - "1: \n" - - "vld2.16 {d4, d5}, [%[sP]] \n"// (3+0d) load 8 16-bits stereo samples - "vld2.16 {d6, d7}, [%[sN]]! \n"// (3) load 8 16-bits stereo samples - "vld1.16 {d16}, [%[coefsP0]:64]! \n"// (1) load 8 16-bits coefs - "vld1.16 {d17}, [%[coefsP1]:64]! \n"// (1) load 8 16-bits coefs for interpolation - "vld1.16 {d20}, [%[coefsN1]:64]! \n"// (1) load 8 16-bits coefs - "vld1.16 {d21}, [%[coefsN0]:64]! \n"// (1) load 8 16-bits coefs for interpolation - - "vsub.s16 d17, d17, d16 \n"// (1) interpolate (step1) 1st set of coefs - "vsub.s16 d21, d21, d20 \n"// (1) interpolate (step1) 2nd set of coets - - "vqrdmulh.s16 d17, d17, d2[0] \n"// (2) interpolate (step2) 1st set of coefs - "vqrdmulh.s16 d21, d21, d2[0] \n"// (2) interpolate (step2) 2nd set of coefs - - "vrev64.16 q2, q2 \n"// (1) reverse 8 frames of the left positive - - "vadd.s16 d16, d16, d17 \n"// (1+1d) interpolate (step3) 1st set - "vadd.s16 d20, d20, d21 \n"// (1+1d) interpolate (step3) 2nd set - - "vmlal.s16 q0, d4, d16 \n"// (1) multiply (reversed) samples left - "vmlal.s16 q4, d5, d16 \n"// (1) multiply (reversed) samples right - "vmlal.s16 q0, d6, d20 \n"// (1) multiply samples left - "vmlal.s16 q4, d7, d20 \n"// (1) multiply samples right - - // moving these ARM before neon seems to be slower - "subs %[count], %[count], #4 \n"// (1) update loop counter - "sub %[sP], %[sP], #16 \n"// move pointer to next set of samples - - // sP used after branch (warning) - "bne 1b \n"// loop - - ASSEMBLY_ACCUMULATE_STEREO - - : [out] "=Uv" (out[0]), - [count] "+r" (count), - [coefsP0] "+r" (coefsP), - [coefsN0] "+r" (coefsN), - [coefsP1] "+r" (coefsP1), - [coefsN1] "+r" (coefsN1), - [sP] "+r" (sP), - [sN] "+r" (sN) - : [lerpP] "r" (lerpP), - [vLR] "r" (volumeLR) - : "cc", "memory", - "q0", "q1", "q2", "q3", - "q4", "q5", "q6", - "q8", "q9", "q10", "q11" - ); -} - -template <> -inline void ProcessL<1, 8>(int32_t* const out, - int count, - const int32_t* coefsP, - const int32_t* coefsN, - const int16_t* sP, - const int16_t* sN, - const int32_t* const volumeLR) -{ - const int CHANNELS = 1; // template specialization does not preserve params - const int STRIDE = 8; - sP -= CHANNELS*((STRIDE>>1)-1); - asm ( - "veor q0, q0, q0 \n"// result, initialize to 0 - - "1: \n" - - "vld1.16 {d4}, [%[sP]] \n"// load 4 16-bits mono samples - "vld1.16 {d6}, [%[sN]]! \n"// load 4 16-bits mono samples - "vld1.32 {q8}, [%[coefsP0]:128]! \n"// load 4 32-bits coefs - "vld1.32 {q10}, [%[coefsN0]:128]! \n"// load 4 32-bits coefs - - "vrev64.16 d4, d4 \n"// reverse 2 frames of the positive side - - "vshll.s16 q12, d4, #15 \n"// (stall) extend samples to 31 bits - "vshll.s16 q14, d6, #15 \n"// extend samples to 31 bits - - "vqrdmulh.s32 q12, q12, q8 \n"// multiply samples by interpolated coef - "vqrdmulh.s32 q14, q14, q10 \n"// multiply samples by interpolated coef - - "vadd.s32 q0, q0, q12 \n"// accumulate result - "vadd.s32 q0, q0, q14 \n"// (stall) accumulate result - - "subs %[count], %[count], #4 \n"// update loop counter - "sub %[sP], %[sP], #8 \n"// move pointer to next set of samples - - "bne 1b \n"// loop - - ASSEMBLY_ACCUMULATE_MONO - - : [out] "=Uv" (out[0]), - [count] "+r" (count), - [coefsP0] "+r" (coefsP), - [coefsN0] "+r" (coefsN), - [sP] "+r" (sP), - [sN] "+r" (sN) - : [vLR] "r" (volumeLR) - : "cc", "memory", - "q0", "q1", "q2", "q3", - "q8", "q9", "q10", "q11", - "q12", "q14" - ); -} - -template <> -inline void ProcessL<2, 8>(int32_t* const out, - int count, - const int32_t* coefsP, - const int32_t* coefsN, - const int16_t* sP, - const int16_t* sN, - const int32_t* const volumeLR) -{ - const int CHANNELS = 2; // template specialization does not preserve params - const int STRIDE = 8; - sP -= CHANNELS*((STRIDE>>1)-1); - asm ( - "veor q0, q0, q0 \n"// result, initialize to 0 - "veor q4, q4, q4 \n"// result, initialize to 0 - - "1: \n" - - "vld2.16 {d4, d5}, [%[sP]] \n"// load 4 16-bits stereo samples - "vld2.16 {d6, d7}, [%[sN]]! \n"// load 4 16-bits stereo samples - "vld1.32 {q8}, [%[coefsP0]:128]! \n"// load 4 32-bits coefs - "vld1.32 {q10}, [%[coefsN0]:128]! \n"// load 4 32-bits coefs - - "vrev64.16 q2, q2 \n"// reverse 2 frames of the positive side - - "vshll.s16 q12, d4, #15 \n"// extend samples to 31 bits - "vshll.s16 q13, d5, #15 \n"// extend samples to 31 bits - - "vshll.s16 q14, d6, #15 \n"// extend samples to 31 bits - "vshll.s16 q15, d7, #15 \n"// extend samples to 31 bits - - "vqrdmulh.s32 q12, q12, q8 \n"// multiply samples by coef - "vqrdmulh.s32 q13, q13, q8 \n"// multiply samples by coef - "vqrdmulh.s32 q14, q14, q10 \n"// multiply samples by coef - "vqrdmulh.s32 q15, q15, q10 \n"// multiply samples by coef - - "vadd.s32 q0, q0, q12 \n"// accumulate result - "vadd.s32 q4, q4, q13 \n"// accumulate result - "vadd.s32 q0, q0, q14 \n"// accumulate result - "vadd.s32 q4, q4, q15 \n"// accumulate result - - "subs %[count], %[count], #4 \n"// update loop counter - "sub %[sP], %[sP], #16 \n"// move pointer to next set of samples - - "bne 1b \n"// loop - - ASSEMBLY_ACCUMULATE_STEREO - - : [out] "=Uv" (out[0]), - [count] "+r" (count), - [coefsP0] "+r" (coefsP), - [coefsN0] "+r" (coefsN), - [sP] "+r" (sP), - [sN] "+r" (sN) - : [vLR] "r" (volumeLR) - : "cc", "memory", - "q0", "q1", "q2", "q3", "q4", - "q8", "q9", "q10", "q11", - "q12", "q13", "q14", "q15" - ); -} - -template <> -inline void Process<1, 8>(int32_t* const out, - int count, - const int32_t* coefsP, - const int32_t* coefsN, - const int32_t* coefsP1, - const int32_t* coefsN1, - const int16_t* sP, - const int16_t* sN, - uint32_t lerpP, - const int32_t* const volumeLR) -{ - const int CHANNELS = 1; // template specialization does not preserve params - const int STRIDE = 8; - sP -= CHANNELS*((STRIDE>>1)-1); - asm ( - "vmov.32 d2[0], %[lerpP] \n"// load the positive phase - "veor q0, q0, q0 \n"// result, initialize to 0 - - "1: \n" - - "vld1.16 {d4}, [%[sP]] \n"// load 4 16-bits mono samples - "vld1.16 {d6}, [%[sN]]! \n"// load 4 16-bits mono samples - "vld1.32 {q8}, [%[coefsP0]:128]! \n"// load 4 32-bits coefs - "vld1.32 {q9}, [%[coefsP1]:128]! \n"// load 4 32-bits coefs for interpolation - "vld1.32 {q10}, [%[coefsN1]:128]! \n"// load 4 32-bits coefs - "vld1.32 {q11}, [%[coefsN0]:128]! \n"// load 4 32-bits coefs for interpolation - - "vrev64.16 d4, d4 \n"// reverse 2 frames of the positive side - - "vsub.s32 q9, q9, q8 \n"// interpolate (step1) 1st set of coefs - "vsub.s32 q11, q11, q10 \n"// interpolate (step1) 2nd set of coets - "vshll.s16 q12, d4, #15 \n"// extend samples to 31 bits - - "vqrdmulh.s32 q9, q9, d2[0] \n"// interpolate (step2) 1st set of coefs - "vqrdmulh.s32 q11, q11, d2[0] \n"// interpolate (step2) 2nd set of coefs - "vshll.s16 q14, d6, #15 \n"// extend samples to 31 bits - - "vadd.s32 q8, q8, q9 \n"// interpolate (step3) 1st set - "vadd.s32 q10, q10, q11 \n"// interpolate (step4) 2nd set - - "vqrdmulh.s32 q12, q12, q8 \n"// multiply samples by interpolated coef - "vqrdmulh.s32 q14, q14, q10 \n"// multiply samples by interpolated coef - - "vadd.s32 q0, q0, q12 \n"// accumulate result - "vadd.s32 q0, q0, q14 \n"// accumulate result - - "subs %[count], %[count], #4 \n"// update loop counter - "sub %[sP], %[sP], #8 \n"// move pointer to next set of samples - - "bne 1b \n"// loop - - ASSEMBLY_ACCUMULATE_MONO - - : [out] "=Uv" (out[0]), - [count] "+r" (count), - [coefsP0] "+r" (coefsP), - [coefsP1] "+r" (coefsP1), - [coefsN0] "+r" (coefsN), - [coefsN1] "+r" (coefsN1), - [sP] "+r" (sP), - [sN] "+r" (sN) - : [lerpP] "r" (lerpP), - [vLR] "r" (volumeLR) - : "cc", "memory", - "q0", "q1", "q2", "q3", - "q8", "q9", "q10", "q11", - "q12", "q14" - ); -} - -template <> -inline -void Process<2, 8>(int32_t* const out, - int count, - const int32_t* coefsP, - const int32_t* coefsN, - const int32_t* coefsP1, - const int32_t* coefsN1, - const int16_t* sP, - const int16_t* sN, - uint32_t lerpP, - const int32_t* const volumeLR) -{ - const int CHANNELS = 2; // template specialization does not preserve params - const int STRIDE = 8; - sP -= CHANNELS*((STRIDE>>1)-1); - asm ( - "vmov.32 d2[0], %[lerpP] \n"// load the positive phase - "veor q0, q0, q0 \n"// result, initialize to 0 - "veor q4, q4, q4 \n"// result, initialize to 0 - - "1: \n" - "vld2.16 {d4, d5}, [%[sP]] \n"// load 4 16-bits stereo samples - "vld2.16 {d6, d7}, [%[sN]]! \n"// load 4 16-bits stereo samples - "vld1.32 {q8}, [%[coefsP0]:128]! \n"// load 4 32-bits coefs - "vld1.32 {q9}, [%[coefsP1]:128]! \n"// load 4 32-bits coefs for interpolation - "vld1.32 {q10}, [%[coefsN1]:128]! \n"// load 4 32-bits coefs - "vld1.32 {q11}, [%[coefsN0]:128]! \n"// load 4 32-bits coefs for interpolation - - "vrev64.16 q2, q2 \n"// (reversed) 2 frames of the positive side - - "vsub.s32 q9, q9, q8 \n"// interpolate (step1) 1st set of coefs - "vsub.s32 q11, q11, q10 \n"// interpolate (step1) 2nd set of coets - "vshll.s16 q12, d4, #15 \n"// extend samples to 31 bits - "vshll.s16 q13, d5, #15 \n"// extend samples to 31 bits - - "vqrdmulh.s32 q9, q9, d2[0] \n"// interpolate (step2) 1st set of coefs - "vqrdmulh.s32 q11, q11, d2[1] \n"// interpolate (step3) 2nd set of coefs - "vshll.s16 q14, d6, #15 \n"// extend samples to 31 bits - "vshll.s16 q15, d7, #15 \n"// extend samples to 31 bits - - "vadd.s32 q8, q8, q9 \n"// interpolate (step3) 1st set - "vadd.s32 q10, q10, q11 \n"// interpolate (step4) 2nd set - - "vqrdmulh.s32 q12, q12, q8 \n"// multiply samples by interpolated coef - "vqrdmulh.s32 q13, q13, q8 \n"// multiply samples by interpolated coef - "vqrdmulh.s32 q14, q14, q10 \n"// multiply samples by interpolated coef - "vqrdmulh.s32 q15, q15, q10 \n"// multiply samples by interpolated coef - - "vadd.s32 q0, q0, q12 \n"// accumulate result - "vadd.s32 q4, q4, q13 \n"// accumulate result - "vadd.s32 q0, q0, q14 \n"// accumulate result - "vadd.s32 q4, q4, q15 \n"// accumulate result - - "subs %[count], %[count], #4 \n"// update loop counter - "sub %[sP], %[sP], #16 \n"// move pointer to next set of samples - - "bne 1b \n"// loop - - ASSEMBLY_ACCUMULATE_STEREO - - : [out] "=Uv" (out[0]), - [count] "+r" (count), - [coefsP0] "+r" (coefsP), - [coefsP1] "+r" (coefsP1), - [coefsN0] "+r" (coefsN), - [coefsN1] "+r" (coefsN1), - [sP] "+r" (sP), - [sN] "+r" (sN) - : [lerpP] "r" (lerpP), - [vLR] "r" (volumeLR) - : "cc", "memory", - "q0", "q1", "q2", "q3", "q4", - "q8", "q9", "q10", "q11", - "q12", "q13", "q14", "q15" - ); + ProcessNeonIntrinsic<2, 16, false>(out, count, coefsP, coefsN, sP, sN, volumeLR, + lerpP, coefsP1, coefsN1); } #endif //USE_NEON -}; // namespace android +} // namespace android #endif /*ANDROID_AUDIO_RESAMPLER_FIR_PROCESS_NEON_H*/ diff --git a/services/audioflinger/AudioResamplerSinc.cpp b/services/audioflinger/AudioResamplerSinc.cpp index e6fb76c..ba9a356 100644 --- a/services/audioflinger/AudioResamplerSinc.cpp +++ b/services/audioflinger/AudioResamplerSinc.cpp @@ -61,135 +61,7 @@ namespace android { * cmd-line: fir -l 7 -s 48000 -c 20478 */ const uint32_t AudioResamplerSinc::mFirCoefsUp[] __attribute__ ((aligned (32))) = { - 0x6d374bc7, 0x111c6ba0, 0xf3240e61, 0x07d14a38, 0xfc509e64, 0x0139cee9, 0xffc8c866, 0xfffcc300, - 0x6d35278a, 0x103e8192, 0xf36b9dfd, 0x07bdfaa5, 0xfc5102d0, 0x013d618d, 0xffc663b9, 0xfffd9592, - 0x6d2ebafe, 0x0f62811a, 0xf3b3d8ac, 0x07a9f399, 0xfc51d9a6, 0x0140bea5, 0xffc41212, 0xfffe631e, - 0x6d24069d, 0x0e8875ad, 0xf3fcb43e, 0x07953976, 0xfc53216f, 0x0143e67c, 0xffc1d373, 0xffff2b9f, - 0x6d150b35, 0x0db06a89, 0xf4462690, 0x077fd0ac, 0xfc54d8ae, 0x0146d965, 0xffbfa7d9, 0xffffef10, - 0x6d01c9e3, 0x0cda6ab5, 0xf4902587, 0x0769bdaf, 0xfc56fdda, 0x014997bb, 0xffbd8f40, 0x0000ad6e, - 0x6cea4418, 0x0c0680fe, 0xf4daa718, 0x07530501, 0xfc598f60, 0x014c21db, 0xffbb89a1, 0x000166b6, - 0x6cce7b97, 0x0b34b7f5, 0xf525a143, 0x073bab28, 0xfc5c8ba5, 0x014e782a, 0xffb996f3, 0x00021ae5, - 0x6cae7272, 0x0a6519f4, 0xf5710a17, 0x0723b4b4, 0xfc5ff105, 0x01509b14, 0xffb7b728, 0x0002c9fd, - 0x6c8a2b0f, 0x0997b116, 0xf5bcd7b1, 0x070b2639, 0xfc63bdd3, 0x01528b08, 0xffb5ea31, 0x000373fb, - 0x6c61a823, 0x08cc873c, 0xf609003f, 0x06f20453, 0xfc67f05a, 0x0154487b, 0xffb42ffc, 0x000418e2, - 0x6c34ecb5, 0x0803a60a, 0xf6557a00, 0x06d853a2, 0xfc6c86dd, 0x0155d3e8, 0xffb28876, 0x0004b8b3, - 0x6c03fc1c, 0x073d16e7, 0xf6a23b44, 0x06be18cd, 0xfc717f97, 0x01572dcf, 0xffb0f388, 0x00055371, - 0x6bced9ff, 0x0678e2fc, 0xf6ef3a6e, 0x06a3587e, 0xfc76d8bc, 0x015856b6, 0xffaf7118, 0x0005e921, - 0x6b958a54, 0x05b71332, 0xf73c6df4, 0x06881761, 0xfc7c9079, 0x01594f25, 0xffae010b, 0x000679c5, - 0x6b581163, 0x04f7b037, 0xf789cc61, 0x066c5a27, 0xfc82a4f4, 0x015a17ab, 0xffaca344, 0x00070564, - 0x6b1673c1, 0x043ac276, 0xf7d74c53, 0x06502583, 0xfc89144d, 0x015ab0db, 0xffab57a1, 0x00078c04, - 0x6ad0b652, 0x0380521c, 0xf824e480, 0x06337e2a, 0xfc8fdc9f, 0x015b1b4e, 0xffaa1e02, 0x00080dab, - 0x6a86de48, 0x02c86715, 0xf8728bb3, 0x061668d2, 0xfc96fbfc, 0x015b579e, 0xffa8f641, 0x00088a62, - 0x6a38f123, 0x0213090c, 0xf8c038d0, 0x05f8ea30, 0xfc9e7074, 0x015b666c, 0xffa7e039, 0x00090230, - 0x69e6f4b1, 0x01603f6e, 0xf90de2d1, 0x05db06fc, 0xfca63810, 0x015b485b, 0xffa6dbc0, 0x0009751e, - 0x6990ef0b, 0x00b01162, 0xf95b80cb, 0x05bcc3ed, 0xfcae50d6, 0x015afe14, 0xffa5e8ad, 0x0009e337, - 0x6936e697, 0x000285d0, 0xf9a909ea, 0x059e25b5, 0xfcb6b8c4, 0x015a8843, 0xffa506d2, 0x000a4c85, - 0x68d8e206, 0xff57a35e, 0xf9f67577, 0x057f310a, 0xfcbf6dd8, 0x0159e796, 0xffa43603, 0x000ab112, - 0x6876e855, 0xfeaf706f, 0xfa43bad2, 0x055fea9d, 0xfcc86e09, 0x01591cc0, 0xffa3760e, 0x000b10ec, - 0x681100c9, 0xfe09f323, 0xfa90d17b, 0x0540571a, 0xfcd1b74c, 0x01582878, 0xffa2c6c2, 0x000b6c1d, - 0x67a732f4, 0xfd673159, 0xfaddb10c, 0x05207b2f, 0xfcdb4793, 0x01570b77, 0xffa227ec, 0x000bc2b3, - 0x673986ac, 0xfcc730aa, 0xfb2a513b, 0x05005b82, 0xfce51ccb, 0x0155c678, 0xffa19957, 0x000c14bb, - 0x66c80413, 0xfc29f670, 0xfb76a9dd, 0x04dffcb6, 0xfcef34e1, 0x01545a3c, 0xffa11acb, 0x000c6244, - 0x6652b392, 0xfb8f87bd, 0xfbc2b2e4, 0x04bf6369, 0xfcf98dbe, 0x0152c783, 0xffa0ac11, 0x000cab5c, - 0x65d99dd5, 0xfaf7e963, 0xfc0e6461, 0x049e9433, 0xfd04254a, 0x01510f13, 0xffa04cf0, 0x000cf012, - 0x655ccbd3, 0xfa631fef, 0xfc59b685, 0x047d93a8, 0xfd0ef969, 0x014f31b2, 0xff9ffd2c, 0x000d3075, - 0x64dc46c3, 0xf9d12fab, 0xfca4a19f, 0x045c6654, 0xfd1a0801, 0x014d3029, 0xff9fbc89, 0x000d6c97, - 0x64581823, 0xf9421c9d, 0xfcef1e20, 0x043b10bd, 0xfd254ef4, 0x014b0b45, 0xff9f8ac9, 0x000da486, - 0x63d049b4, 0xf8b5ea87, 0xfd392498, 0x04199760, 0xfd30cc24, 0x0148c3d2, 0xff9f67ae, 0x000dd854, - 0x6344e578, 0xf82c9ce7, 0xfd82adba, 0x03f7feb4, 0xfd3c7d73, 0x01465a9f, 0xff9f52f7, 0x000e0812, - 0x62b5f5b2, 0xf7a636fa, 0xfdcbb25a, 0x03d64b27, 0xfd4860c2, 0x0143d07f, 0xff9f4c65, 0x000e33d3, - 0x622384e8, 0xf722bbb5, 0xfe142b6e, 0x03b4811d, 0xfd5473f3, 0x01412643, 0xff9f53b4, 0x000e5ba7, - 0x618d9ddc, 0xf6a22dcf, 0xfe5c120f, 0x0392a4f4, 0xfd60b4e7, 0x013e5cc0, 0xff9f68a1, 0x000e7fa1, - 0x60f44b91, 0xf6248fb6, 0xfea35f79, 0x0370bafc, 0xfd6d2180, 0x013b74ca, 0xff9f8ae9, 0x000e9fd5, - 0x60579947, 0xf5a9e398, 0xfeea0d0c, 0x034ec77f, 0xfd79b7a1, 0x01386f3a, 0xff9fba47, 0x000ebc54, - 0x5fb79278, 0xf5322b61, 0xff30144a, 0x032ccebb, 0xfd86752e, 0x01354ce7, 0xff9ff674, 0x000ed533, - 0x5f1442dc, 0xf4bd68b6, 0xff756edc, 0x030ad4e1, 0xfd93580d, 0x01320ea9, 0xffa03f2b, 0x000eea84, - 0x5e6db665, 0xf44b9cfe, 0xffba168d, 0x02e8de19, 0xfda05e23, 0x012eb55a, 0xffa09425, 0x000efc5c, - 0x5dc3f93c, 0xf3dcc959, 0xfffe054e, 0x02c6ee7f, 0xfdad855b, 0x012b41d3, 0xffa0f519, 0x000f0ace, - 0x5d1717c4, 0xf370eea9, 0x00413536, 0x02a50a22, 0xfdbacb9e, 0x0127b4f1, 0xffa161bf, 0x000f15ef, - 0x5c671e96, 0xf3080d8c, 0x0083a081, 0x02833506, 0xfdc82edb, 0x01240f8e, 0xffa1d9cf, 0x000f1dd2, - 0x5bb41a80, 0xf2a2265e, 0x00c54190, 0x02617321, 0xfdd5ad01, 0x01205285, 0xffa25cfe, 0x000f228d, - 0x5afe1886, 0xf23f393b, 0x010612eb, 0x023fc85c, 0xfde34403, 0x011c7eb2, 0xffa2eb04, 0x000f2434, - 0x5a4525df, 0xf1df45fd, 0x01460f41, 0x021e3891, 0xfdf0f1d6, 0x011894f0, 0xffa38395, 0x000f22dc, - 0x59894ff3, 0xf1824c3e, 0x01853165, 0x01fcc78f, 0xfdfeb475, 0x0114961b, 0xffa42668, 0x000f1e99, - 0x58caa45b, 0xf1284b58, 0x01c37452, 0x01db7914, 0xfe0c89db, 0x0110830f, 0xffa4d332, 0x000f1781, - 0x580930e1, 0xf0d14267, 0x0200d32c, 0x01ba50d2, 0xfe1a7009, 0x010c5ca6, 0xffa589a6, 0x000f0da8, - 0x5745037c, 0xf07d3043, 0x023d493c, 0x0199526b, 0xfe286505, 0x010823ba, 0xffa6497c, 0x000f0125, - 0x567e2a51, 0xf02c138a, 0x0278d1f2, 0x01788170, 0xfe3666d5, 0x0103d927, 0xffa71266, 0x000ef20b, - 0x55b4b3af, 0xefddea9a, 0x02b368e6, 0x0157e166, 0xfe447389, 0x00ff7dc4, 0xffa7e41a, 0x000ee070, - 0x54e8ae13, 0xef92b393, 0x02ed09d7, 0x013775bf, 0xfe528931, 0x00fb126b, 0xffa8be4c, 0x000ecc69, - 0x541a281e, 0xef4a6c58, 0x0325b0ad, 0x011741df, 0xfe60a5e5, 0x00f697f3, 0xffa9a0b1, 0x000eb60b, - 0x5349309e, 0xef051290, 0x035d5977, 0x00f7491a, 0xfe6ec7c0, 0x00f20f32, 0xffaa8afe, 0x000e9d6b, - 0x5275d684, 0xeec2a3a3, 0x0394006a, 0x00d78eb3, 0xfe7cece2, 0x00ed78ff, 0xffab7ce7, 0x000e829e, - 0x51a028e8, 0xee831cc3, 0x03c9a1e5, 0x00b815da, 0xfe8b1373, 0x00e8d62d, 0xffac7621, 0x000e65ba, - 0x50c83704, 0xee467ae1, 0x03fe3a6f, 0x0098e1b3, 0xfe99399f, 0x00e4278f, 0xffad7662, 0x000e46d3, - 0x4fee1037, 0xee0cbab9, 0x0431c6b5, 0x0079f54c, 0xfea75d97, 0x00df6df7, 0xffae7d5f, 0x000e25fd, - 0x4f11c3fe, 0xedd5d8ca, 0x0464438c, 0x005b53a4, 0xfeb57d92, 0x00daaa34, 0xffaf8acd, 0x000e034f, - 0x4e3361f7, 0xeda1d15c, 0x0495adf2, 0x003cffa9, 0xfec397cf, 0x00d5dd16, 0xffb09e63, 0x000ddedb, - 0x4d52f9df, 0xed70a07d, 0x04c6030d, 0x001efc35, 0xfed1aa92, 0x00d10769, 0xffb1b7d8, 0x000db8b7, - 0x4c709b8e, 0xed424205, 0x04f54029, 0x00014c12, 0xfedfb425, 0x00cc29f7, 0xffb2d6e1, 0x000d90f6, - 0x4b8c56f8, 0xed16b196, 0x052362ba, 0xffe3f1f7, 0xfeedb2da, 0x00c7458a, 0xffb3fb37, 0x000d67ae, - 0x4aa63c2c, 0xecedea99, 0x0550685d, 0xffc6f08a, 0xfefba508, 0x00c25ae8, 0xffb52490, 0x000d3cf1, - 0x49be5b50, 0xecc7e845, 0x057c4ed4, 0xffaa4a5d, 0xff09890f, 0x00bd6ad7, 0xffb652a7, 0x000d10d5, - 0x48d4c4a2, 0xeca4a59b, 0x05a7140b, 0xff8e01f1, 0xff175d53, 0x00b87619, 0xffb78533, 0x000ce36b, - 0x47e98874, 0xec841d68, 0x05d0b612, 0xff7219b3, 0xff252042, 0x00b37d70, 0xffb8bbed, 0x000cb4c8, - 0x46fcb72d, 0xec664a48, 0x05f93324, 0xff5693fe, 0xff32d04f, 0x00ae8198, 0xffb9f691, 0x000c84ff, - 0x460e6148, 0xec4b26a2, 0x0620899e, 0xff3b731b, 0xff406bf8, 0x00a9834e, 0xffbb34d8, 0x000c5422, - 0x451e9750, 0xec32acb0, 0x0646b808, 0xff20b93e, 0xff4df1be, 0x00a4834c, 0xffbc767f, 0x000c2245, - 0x442d69de, 0xec1cd677, 0x066bbd0d, 0xff066889, 0xff5b602c, 0x009f8249, 0xffbdbb42, 0x000bef79, - 0x433ae99c, 0xec099dcf, 0x068f9781, 0xfeec830d, 0xff68b5d5, 0x009a80f8, 0xffbf02dd, 0x000bbbd2, - 0x4247273f, 0xebf8fc64, 0x06b2465b, 0xfed30ac5, 0xff75f153, 0x0095800c, 0xffc04d0f, 0x000b8760, - 0x41523389, 0xebeaebaf, 0x06d3c8bb, 0xfeba0199, 0xff831148, 0x00908034, 0xffc19996, 0x000b5235, - 0x405c1f43, 0xebdf6500, 0x06f41de3, 0xfea16960, 0xff90145e, 0x008b821b, 0xffc2e832, 0x000b1c64, - 0x3f64fb40, 0xebd6617b, 0x0713453d, 0xfe8943dc, 0xff9cf947, 0x0086866b, 0xffc438a3, 0x000ae5fc, - 0x3e6cd85b, 0xebcfda19, 0x07313e56, 0xfe7192bd, 0xffa9bebe, 0x00818dcb, 0xffc58aaa, 0x000aaf0f, - 0x3d73c772, 0xebcbc7a7, 0x074e08e0, 0xfe5a579d, 0xffb66386, 0x007c98de, 0xffc6de09, 0x000a77ac, - 0x3c79d968, 0xebca22cc, 0x0769a4b2, 0xfe439407, 0xffc2e669, 0x0077a845, 0xffc83285, 0x000a3fe5, - 0x3b7f1f23, 0xebcae405, 0x078411c7, 0xfe2d496f, 0xffcf463a, 0x0072bc9d, 0xffc987e0, 0x000a07c9, - 0x3a83a989, 0xebce03aa, 0x079d503b, 0xfe177937, 0xffdb81d6, 0x006dd680, 0xffcadde1, 0x0009cf67, - 0x3987897f, 0xebd379eb, 0x07b56051, 0xfe0224b0, 0xffe79820, 0x0068f687, 0xffcc344c, 0x000996ce, - 0x388acfe9, 0xebdb3ed5, 0x07cc426c, 0xfded4d13, 0xfff38806, 0x00641d44, 0xffcd8aeb, 0x00095e0e, - 0x378d8da8, 0xebe54a4f, 0x07e1f712, 0xfdd8f38b, 0xffff507b, 0x005f4b4a, 0xffcee183, 0x00092535, - 0x368fd397, 0xebf1941f, 0x07f67eec, 0xfdc5192d, 0x000af07f, 0x005a8125, 0xffd037e0, 0x0008ec50, - 0x3591b28b, 0xec0013e8, 0x0809dac3, 0xfdb1befc, 0x00166718, 0x0055bf60, 0xffd18dcc, 0x0008b36e, - 0x34933b50, 0xec10c12c, 0x081c0b84, 0xfd9ee5e7, 0x0021b355, 0x00510682, 0xffd2e311, 0x00087a9c, - 0x33947eab, 0xec23934f, 0x082d1239, 0xfd8c8ecc, 0x002cd44d, 0x004c570f, 0xffd4377d, 0x000841e8, - 0x32958d55, 0xec388194, 0x083cf010, 0xfd7aba74, 0x0037c922, 0x0047b186, 0xffd58ade, 0x0008095d, - 0x319677fa, 0xec4f8322, 0x084ba654, 0xfd696998, 0x004290fc, 0x00431666, 0xffd6dd02, 0x0007d108, - 0x30974f3b, 0xec688f02, 0x08593671, 0xfd589cdc, 0x004d2b0e, 0x003e8628, 0xffd82dba, 0x000798f5, - 0x2f9823a8, 0xec839c22, 0x0865a1f1, 0xfd4854d3, 0x00579691, 0x003a0141, 0xffd97cd6, 0x00076130, - 0x2e9905c1, 0xeca0a156, 0x0870ea7e, 0xfd3891fd, 0x0061d2ca, 0x00358824, 0xffdaca2a, 0x000729c4, - 0x2d9a05f4, 0xecbf9558, 0x087b11de, 0xfd2954c8, 0x006bdf05, 0x00311b41, 0xffdc1588, 0x0006f2bb, - 0x2c9b349e, 0xece06ecb, 0x088419f6, 0xfd1a9d91, 0x0075ba95, 0x002cbb03, 0xffdd5ec6, 0x0006bc21, - 0x2b9ca203, 0xed032439, 0x088c04c8, 0xfd0c6ca2, 0x007f64da, 0x002867d2, 0xffdea5bb, 0x000685ff, - 0x2a9e5e57, 0xed27ac16, 0x0892d470, 0xfcfec233, 0x0088dd38, 0x00242213, 0xffdfea3c, 0x0006505f, - 0x29a079b2, 0xed4dfcc2, 0x08988b2a, 0xfcf19e6b, 0x0092231e, 0x001fea27, 0xffe12c22, 0x00061b4b, - 0x28a30416, 0xed760c88, 0x089d2b4a, 0xfce50161, 0x009b3605, 0x001bc06b, 0xffe26b48, 0x0005e6cb, - 0x27a60d6a, 0xed9fd1a2, 0x08a0b740, 0xfcd8eb17, 0x00a4156b, 0x0017a53b, 0xffe3a788, 0x0005b2e8, - 0x26a9a57b, 0xedcb4237, 0x08a33196, 0xfccd5b82, 0x00acc0da, 0x001398ec, 0xffe4e0bf, 0x00057faa, - 0x25addbf9, 0xedf8545b, 0x08a49cf0, 0xfcc25285, 0x00b537e1, 0x000f9bd2, 0xffe616c8, 0x00054d1a, - 0x24b2c075, 0xee26fe17, 0x08a4fc0d, 0xfcb7cff0, 0x00bd7a1c, 0x000bae3c, 0xffe74984, 0x00051b3e, - 0x23b86263, 0xee573562, 0x08a451c0, 0xfcadd386, 0x00c5872a, 0x0007d075, 0xffe878d3, 0x0004ea1d, - 0x22bed116, 0xee88f026, 0x08a2a0f8, 0xfca45cf7, 0x00cd5eb7, 0x000402c8, 0xffe9a494, 0x0004b9c0, - 0x21c61bc0, 0xeebc2444, 0x089fecbb, 0xfc9b6be5, 0x00d50075, 0x00004579, 0xffeaccaa, 0x00048a2b, - 0x20ce516f, 0xeef0c78d, 0x089c3824, 0xfc92ffe1, 0x00dc6c1e, 0xfffc98c9, 0xffebf0fa, 0x00045b65, - 0x1fd7810f, 0xef26cfca, 0x08978666, 0xfc8b186d, 0x00e3a175, 0xfff8fcf7, 0xffed1166, 0x00042d74, - 0x1ee1b965, 0xef5e32bd, 0x0891dac8, 0xfc83b4fc, 0x00eaa045, 0xfff5723d, 0xffee2dd7, 0x0004005e, - 0x1ded0911, 0xef96e61c, 0x088b38a9, 0xfc7cd4f0, 0x00f16861, 0xfff1f8d2, 0xffef4632, 0x0003d426, - 0x1cf97e8b, 0xefd0df9a, 0x0883a378, 0xfc76779e, 0x00f7f9a3, 0xffee90eb, 0xfff05a60, 0x0003a8d2, - 0x1c072823, 0xf00c14e1, 0x087b1ebc, 0xfc709c4d, 0x00fe53ef, 0xffeb3ab8, 0xfff16a4a, 0x00037e65, - 0x1b1613ff, 0xf0487b98, 0x0871ae0d, 0xfc6b4233, 0x0104772e, 0xffe7f666, 0xfff275db, 0x000354e5, - 0x1a26501b, 0xf0860962, 0x08675516, 0xfc66687a, 0x010a6353, 0xffe4c41e, 0xfff37d00, 0x00032c54, - 0x1937ea47, 0xf0c4b3e0, 0x085c1794, 0xfc620e3d, 0x01101858, 0xffe1a408, 0xfff47fa5, 0x000304b7, - 0x184af025, 0xf10470b0, 0x084ff957, 0xfc5e328c, 0x0115963d, 0xffde9646, 0xfff57db8, 0x0002de0e, - 0x175f6f2b, 0xf1453571, 0x0842fe3d, 0xfc5ad465, 0x011add0b, 0xffdb9af8, 0xfff67729, 0x0002b85f, - 0x1675749e, 0xf186f7c0, 0x08352a35, 0xfc57f2be, 0x011fecd3, 0xffd8b23b, 0xfff76be9, 0x000293aa, - 0x158d0d95, 0xf1c9ad40, 0x0826813e, 0xfc558c7c, 0x0124c5ab, 0xffd5dc28, 0xfff85be8, 0x00026ff2, - 0x14a646f6, 0xf20d4b92, 0x08170767, 0xfc53a07b, 0x012967b1, 0xffd318d6, 0xfff9471b, 0x00024d39, - 0x13c12d73, 0xf251c85d, 0x0806c0cb, 0xfc522d88, 0x012dd30a, 0xffd06858, 0xfffa2d74, 0x00022b7f, - 0x12ddcd8f, 0xf297194d, 0x07f5b193, 0xfc513266, 0x013207e4, 0xffcdcabe, 0xfffb0ee9, 0x00020ac7, - 0x11fc3395, 0xf2dd3411, 0x07e3ddf7, 0xfc50adcc, 0x01360670, 0xffcb4014, 0xfffbeb70, 0x0001eb10, - 0x111c6ba0, 0xf3240e61, 0x07d14a38, 0xfc509e64, 0x0139cee9, 0xffc8c866, 0xfffcc300, 0x0001cc5c, +#include "AudioResamplerSincUp.h" }; /* @@ -197,135 +69,7 @@ const uint32_t AudioResamplerSinc::mFirCoefsUp[] __attribute__ ((aligned (32))) * cmd-line: fir -l 7 -s 48000 -c 17189 */ const uint32_t AudioResamplerSinc::mFirCoefsDown[] __attribute__ ((aligned (32))) = { - 0x5bacb6f4, 0x1ded1a1d, 0xf0398d56, 0x0394f674, 0x0193a5f9, 0xfe66dbeb, 0x00791043, 0xfffe6631, - 0x5bab6c81, 0x1d3ddccd, 0xf0421d2c, 0x03af9995, 0x01818dc9, 0xfe6bb63e, 0x0079812a, 0xfffdc37d, - 0x5ba78d37, 0x1c8f2cf9, 0xf04beb1d, 0x03c9a04a, 0x016f8aca, 0xfe70a511, 0x0079e34d, 0xfffd2545, - 0x5ba1194f, 0x1be11231, 0xf056f2c7, 0x03e309fe, 0x015d9e64, 0xfe75a79f, 0x007a36e2, 0xfffc8b86, - 0x5b981122, 0x1b3393f8, 0xf0632fb7, 0x03fbd625, 0x014bc9fa, 0xfe7abd23, 0x007a7c20, 0xfffbf639, - 0x5b8c7530, 0x1a86b9bf, 0xf0709d74, 0x04140449, 0x013a0ee9, 0xfe7fe4db, 0x007ab33d, 0xfffb655b, - 0x5b7e461a, 0x19da8ae5, 0xf07f3776, 0x042b93fd, 0x01286e86, 0xfe851e05, 0x007adc72, 0xfffad8e4, - 0x5b6d84a8, 0x192f0eb7, 0xf08ef92d, 0x044284e6, 0x0116ea22, 0xfe8a67dd, 0x007af7f6, 0xfffa50ce, - 0x5b5a31c6, 0x18844c70, 0xf09fddfe, 0x0458d6b7, 0x01058306, 0xfe8fc1a5, 0x007b0603, 0xfff9cd12, - 0x5b444e81, 0x17da4b37, 0xf0b1e143, 0x046e8933, 0x00f43a74, 0xfe952a9b, 0x007b06d4, 0xfff94da9, - 0x5b2bdc0e, 0x17311222, 0xf0c4fe50, 0x04839c29, 0x00e311a9, 0xfe9aa201, 0x007afaa1, 0xfff8d28c, - 0x5b10dbc2, 0x1688a832, 0xf0d9306d, 0x04980f79, 0x00d209db, 0xfea02719, 0x007ae1a7, 0xfff85bb1, - 0x5af34f18, 0x15e11453, 0xf0ee72db, 0x04abe310, 0x00c12439, 0xfea5b926, 0x007abc20, 0xfff7e910, - 0x5ad337af, 0x153a5d5e, 0xf104c0d2, 0x04bf16e9, 0x00b061eb, 0xfeab576d, 0x007a8a49, 0xfff77a9f, - 0x5ab09748, 0x14948a16, 0xf11c1583, 0x04d1ab0d, 0x009fc413, 0xfeb10134, 0x007a4c5d, 0xfff71057, - 0x5a8b6fc7, 0x13efa12c, 0xf1346c17, 0x04e39f93, 0x008f4bcb, 0xfeb6b5c0, 0x007a029a, 0xfff6aa2b, - 0x5a63c336, 0x134ba937, 0xf14dbfb1, 0x04f4f4a2, 0x007efa29, 0xfebc745c, 0x0079ad3d, 0xfff64812, - 0x5a3993c0, 0x12a8a8bb, 0xf1680b6e, 0x0505aa6a, 0x006ed038, 0xfec23c50, 0x00794c82, 0xfff5ea02, - 0x5a0ce3b2, 0x1206a625, 0xf1834a63, 0x0515c12d, 0x005ecf01, 0xfec80ce8, 0x0078e0a9, 0xfff58ff0, - 0x59ddb57f, 0x1165a7cc, 0xf19f77a0, 0x05253938, 0x004ef782, 0xfecde571, 0x007869ee, 0xfff539cf, - 0x59ac0bba, 0x10c5b3ef, 0xf1bc8e31, 0x053412e4, 0x003f4ab4, 0xfed3c538, 0x0077e891, 0xfff4e794, - 0x5977e919, 0x1026d0b8, 0xf1da891b, 0x05424e9b, 0x002fc98a, 0xfed9ab8f, 0x00775ccf, 0xfff49934, - 0x59415075, 0x0f890437, 0xf1f96360, 0x054feccf, 0x002074ed, 0xfedf97c6, 0x0076c6e8, 0xfff44ea3, - 0x590844c9, 0x0eec5465, 0xf21917ff, 0x055cee03, 0x00114dc3, 0xfee58932, 0x00762719, 0xfff407d2, - 0x58ccc930, 0x0e50c723, 0xf239a1ef, 0x056952c3, 0x000254e8, 0xfeeb7f27, 0x00757da3, 0xfff3c4b7, - 0x588ee0ea, 0x0db6623b, 0xf25afc29, 0x05751baa, 0xfff38b32, 0xfef178fc, 0x0074cac4, 0xfff38542, - 0x584e8f56, 0x0d1d2b5d, 0xf27d219f, 0x0580495c, 0xffe4f171, 0xfef7760c, 0x00740ebb, 0xfff34968, - 0x580bd7f4, 0x0c85281f, 0xf2a00d43, 0x058adc8d, 0xffd6886d, 0xfefd75af, 0x007349c7, 0xfff3111b, - 0x57c6be67, 0x0bee5dff, 0xf2c3ba04, 0x0594d5fa, 0xffc850e6, 0xff037744, 0x00727c27, 0xfff2dc4c, - 0x577f4670, 0x0b58d262, 0xf2e822ce, 0x059e366c, 0xffba4b98, 0xff097a29, 0x0071a61b, 0xfff2aaef, - 0x573573f2, 0x0ac48a92, 0xf30d428e, 0x05a6feb9, 0xffac7936, 0xff0f7dbf, 0x0070c7e1, 0xfff27cf3, - 0x56e94af1, 0x0a318bc1, 0xf333142f, 0x05af2fbf, 0xff9eda6d, 0xff15816a, 0x006fe1b8, 0xfff2524c, - 0x569acf90, 0x099fdb04, 0xf359929a, 0x05b6ca6b, 0xff916fe1, 0xff1b848e, 0x006ef3df, 0xfff22aea, - 0x564a0610, 0x090f7d57, 0xf380b8ba, 0x05bdcfb2, 0xff843a32, 0xff218692, 0x006dfe94, 0xfff206bf, - 0x55f6f2d3, 0x0880779d, 0xf3a88179, 0x05c44095, 0xff7739f7, 0xff2786e1, 0x006d0217, 0xfff1e5bb, - 0x55a19a5c, 0x07f2ce9b, 0xf3d0e7c2, 0x05ca1e1f, 0xff6a6fc1, 0xff2d84e5, 0x006bfea4, 0xfff1c7d0, - 0x554a0148, 0x076686fc, 0xf3f9e680, 0x05cf6965, 0xff5ddc1a, 0xff33800e, 0x006af47b, 0xfff1acef, - 0x54f02c56, 0x06dba551, 0xf42378a0, 0x05d42387, 0xff517f86, 0xff3977cb, 0x0069e3d9, 0xfff19508, - 0x54942061, 0x06522e0f, 0xf44d9912, 0x05d84daf, 0xff455a80, 0xff3f6b8f, 0x0068ccfa, 0xfff1800b, - 0x5435e263, 0x05ca258f, 0xf47842c5, 0x05dbe90f, 0xff396d7f, 0xff455acf, 0x0067b01e, 0xfff16de9, - 0x53d57774, 0x0543900d, 0xf4a370ad, 0x05def6e4, 0xff2db8f2, 0xff4b4503, 0x00668d80, 0xfff15e93, - 0x5372e4c6, 0x04be71ab, 0xf4cf1dbf, 0x05e17873, 0xff223d40, 0xff5129a3, 0x0065655d, 0xfff151f9, - 0x530e2fac, 0x043ace6e, 0xf4fb44f4, 0x05e36f0d, 0xff16faca, 0xff57082e, 0x006437f1, 0xfff1480b, - 0x52a75d90, 0x03b8aa40, 0xf527e149, 0x05e4dc08, 0xff0bf1ed, 0xff5ce021, 0x00630577, 0xfff140b9, - 0x523e73fd, 0x033808eb, 0xf554edbd, 0x05e5c0c6, 0xff0122fc, 0xff62b0fd, 0x0061ce2c, 0xfff13bf3, - 0x51d37897, 0x02b8ee22, 0xf5826555, 0x05e61eae, 0xfef68e45, 0xff687a47, 0x00609249, 0xfff139aa, - 0x5166711c, 0x023b5d76, 0xf5b0431a, 0x05e5f733, 0xfeec340f, 0xff6e3b84, 0x005f520a, 0xfff139cd, - 0x50f76368, 0x01bf5a5e, 0xf5de8218, 0x05e54bcd, 0xfee2149b, 0xff73f43d, 0x005e0da8, 0xfff13c4c, - 0x5086556f, 0x0144e834, 0xf60d1d63, 0x05e41dfe, 0xfed83023, 0xff79a3fe, 0x005cc55c, 0xfff14119, - 0x50134d3e, 0x00cc0a36, 0xf63c1012, 0x05e26f4e, 0xfece86db, 0xff7f4a54, 0x005b7961, 0xfff14821, - 0x4f9e50ff, 0x0054c382, 0xf66b5544, 0x05e0414d, 0xfec518f1, 0xff84e6d0, 0x005a29ed, 0xfff15156, - 0x4f2766f2, 0xffdf171b, 0xf69ae81d, 0x05dd9593, 0xfebbe68c, 0xff8a7905, 0x0058d738, 0xfff15ca8, - 0x4eae9571, 0xff6b07e7, 0xf6cac3c7, 0x05da6dbe, 0xfeb2efcd, 0xff900089, 0x0057817b, 0xfff16a07, - 0x4e33e2ee, 0xfef898ae, 0xf6fae373, 0x05d6cb72, 0xfeaa34d0, 0xff957cf4, 0x005628ec, 0xfff17962, - 0x4db755f3, 0xfe87cc1b, 0xf72b425b, 0x05d2b05c, 0xfea1b5a9, 0xff9aede0, 0x0054cdc0, 0xfff18aab, - 0x4d38f520, 0xfe18a4bc, 0xf75bdbbd, 0x05ce1e2d, 0xfe997268, 0xffa052ec, 0x0053702d, 0xfff19dd1, - 0x4cb8c72e, 0xfdab2501, 0xf78caae0, 0x05c9169d, 0xfe916b15, 0xffa5abb8, 0x00521068, 0xfff1b2c5, - 0x4c36d2eb, 0xfd3f4f3d, 0xf7bdab16, 0x05c39b6a, 0xfe899fb2, 0xffaaf7e6, 0x0050aea5, 0xfff1c976, - 0x4bb31f3c, 0xfcd525a5, 0xf7eed7b4, 0x05bdae57, 0xfe82103f, 0xffb0371c, 0x004f4b17, 0xfff1e1d6, - 0x4b2db31a, 0xfc6caa53, 0xf8202c1c, 0x05b7512e, 0xfe7abcb1, 0xffb56902, 0x004de5f1, 0xfff1fbd5, - 0x4aa69594, 0xfc05df40, 0xf851a3b6, 0x05b085bc, 0xfe73a4fb, 0xffba8d44, 0x004c7f66, 0xfff21764, - 0x4a1dcdce, 0xfba0c64b, 0xf88339f5, 0x05a94dd5, 0xfe6cc909, 0xffbfa38d, 0x004b17a6, 0xfff23473, - 0x499362ff, 0xfb3d6133, 0xf8b4ea55, 0x05a1ab52, 0xfe6628c1, 0xffc4ab8f, 0x0049aee3, 0xfff252f3, - 0x49075c72, 0xfadbb19a, 0xf8e6b059, 0x0599a00e, 0xfe5fc405, 0xffc9a4fc, 0x0048454b, 0xfff272d6, - 0x4879c185, 0xfa7bb908, 0xf9188793, 0x05912dea, 0xfe599aaf, 0xffce8f8a, 0x0046db0f, 0xfff2940b, - 0x47ea99a9, 0xfa1d78e3, 0xf94a6b9b, 0x058856cd, 0xfe53ac97, 0xffd36af1, 0x0045705c, 0xfff2b686, - 0x4759ec60, 0xf9c0f276, 0xf97c5815, 0x057f1c9e, 0xfe4df98e, 0xffd836eb, 0x00440561, 0xfff2da36, - 0x46c7c140, 0xf96626f0, 0xf9ae48af, 0x0575814c, 0xfe48815e, 0xffdcf336, 0x00429a4a, 0xfff2ff0d, - 0x46341fed, 0xf90d1761, 0xf9e03924, 0x056b86c6, 0xfe4343d0, 0xffe19f91, 0x00412f43, 0xfff324fd, - 0x459f101d, 0xf8b5c4be, 0xfa122537, 0x05612f00, 0xfe3e40a6, 0xffe63bc0, 0x003fc478, 0xfff34bf9, - 0x45089996, 0xf8602fdc, 0xfa4408ba, 0x05567bf1, 0xfe39779a, 0xffeac787, 0x003e5a12, 0xfff373f0, - 0x4470c42d, 0xf80c5977, 0xfa75df87, 0x054b6f92, 0xfe34e867, 0xffef42af, 0x003cf03d, 0xfff39cd7, - 0x43d797c7, 0xf7ba422b, 0xfaa7a586, 0x05400be1, 0xfe3092bf, 0xfff3ad01, 0x003b871f, 0xfff3c69f, - 0x433d1c56, 0xf769ea78, 0xfad956ab, 0x053452dc, 0xfe2c7650, 0xfff8064b, 0x003a1ee3, 0xfff3f13a, - 0x42a159dc, 0xf71b52c4, 0xfb0aeef6, 0x05284685, 0xfe2892c5, 0xfffc4e5c, 0x0038b7ae, 0xfff41c9c, - 0x42045865, 0xf6ce7b57, 0xfb3c6a73, 0x051be8dd, 0xfe24e7c3, 0x00008507, 0x003751a7, 0xfff448b7, - 0x4166200e, 0xf683645a, 0xfb6dc53c, 0x050f3bec, 0xfe2174ec, 0x0004aa1f, 0x0035ecf4, 0xfff4757e, - 0x40c6b8fd, 0xf63a0ddf, 0xfb9efb77, 0x050241b6, 0xfe1e39da, 0x0008bd7c, 0x003489b9, 0xfff4a2e5, - 0x40262b65, 0xf5f277d9, 0xfbd00956, 0x04f4fc46, 0xfe1b3628, 0x000cbef7, 0x0033281a, 0xfff4d0de, - 0x3f847f83, 0xf5aca21f, 0xfc00eb1b, 0x04e76da3, 0xfe18696a, 0x0010ae6e, 0x0031c83a, 0xfff4ff5d, - 0x3ee1bda2, 0xf5688c6d, 0xfc319d13, 0x04d997d8, 0xfe15d32f, 0x00148bbd, 0x00306a3b, 0xfff52e57, - 0x3e3dee13, 0xf5263665, 0xfc621b9a, 0x04cb7cf2, 0xfe137304, 0x001856c7, 0x002f0e3f, 0xfff55dbf, - 0x3d991932, 0xf4e59f8a, 0xfc926319, 0x04bd1efb, 0xfe114872, 0x001c0f6e, 0x002db466, 0xfff58d89, - 0x3cf34766, 0xf4a6c748, 0xfcc27008, 0x04ae8000, 0xfe0f52fc, 0x001fb599, 0x002c5cd0, 0xfff5bdaa, - 0x3c4c811c, 0xf469aced, 0xfcf23eec, 0x049fa20f, 0xfe0d9224, 0x0023492f, 0x002b079a, 0xfff5ee17, - 0x3ba4cec9, 0xf42e4faf, 0xfd21cc59, 0x04908733, 0xfe0c0567, 0x0026ca1c, 0x0029b4e4, 0xfff61ec5, - 0x3afc38eb, 0xf3f4aea6, 0xfd5114f0, 0x0481317a, 0xfe0aac3f, 0x002a384c, 0x002864c9, 0xfff64fa8, - 0x3a52c805, 0xf3bcc8d3, 0xfd801564, 0x0471a2ef, 0xfe098622, 0x002d93ae, 0x00271766, 0xfff680b5, - 0x39a884a1, 0xf3869d1a, 0xfdaeca73, 0x0461dda0, 0xfe089283, 0x0030dc34, 0x0025ccd7, 0xfff6b1e4, - 0x38fd774e, 0xf3522a49, 0xfddd30eb, 0x0451e396, 0xfe07d0d3, 0x003411d2, 0x00248535, 0xfff6e329, - 0x3851a8a2, 0xf31f6f0f, 0xfe0b45aa, 0x0441b6dd, 0xfe07407d, 0x0037347d, 0x0023409a, 0xfff7147a, - 0x37a52135, 0xf2ee6a07, 0xfe39059b, 0x0431597d, 0xfe06e0eb, 0x003a442e, 0x0021ff1f, 0xfff745cd, - 0x36f7e9a4, 0xf2bf19ae, 0xfe666dbc, 0x0420cd80, 0xfe06b184, 0x003d40e0, 0x0020c0dc, 0xfff7771a, - 0x364a0a90, 0xf2917c6d, 0xfe937b15, 0x041014eb, 0xfe06b1ac, 0x00402a8e, 0x001f85e6, 0xfff7a857, - 0x359b8c9d, 0xf265908f, 0xfec02ac2, 0x03ff31c3, 0xfe06e0c4, 0x00430137, 0x001e4e56, 0xfff7d97a, - 0x34ec786f, 0xf23b544b, 0xfeec79ec, 0x03ee260d, 0xfe073e2a, 0x0045c4dd, 0x001d1a3f, 0xfff80a7c, - 0x343cd6af, 0xf212c5be, 0xff1865cd, 0x03dcf3ca, 0xfe07c93a, 0x00487582, 0x001be9b7, 0xfff83b52, - 0x338cb004, 0xf1ebe2ec, 0xff43ebac, 0x03cb9cf9, 0xfe08814e, 0x004b132b, 0x001abcd0, 0xfff86bf6, - 0x32dc0d17, 0xf1c6a9c3, 0xff6f08e4, 0x03ba2398, 0xfe0965bc, 0x004d9dde, 0x0019939d, 0xfff89c60, - 0x322af693, 0xf1a3181a, 0xff99badb, 0x03a889a1, 0xfe0a75da, 0x005015a5, 0x00186e31, 0xfff8cc86, - 0x3179751f, 0xf1812bb0, 0xffc3ff0c, 0x0396d10c, 0xfe0bb0f9, 0x00527a8a, 0x00174c9c, 0xfff8fc62, - 0x30c79163, 0xf160e22d, 0xffedd2fd, 0x0384fbd1, 0xfe0d166b, 0x0054cc9a, 0x00162eef, 0xfff92bec, - 0x30155404, 0xf1423924, 0x00173447, 0x03730be0, 0xfe0ea57e, 0x00570be4, 0x00151538, 0xfff95b1e, - 0x2f62c5a7, 0xf1252e0f, 0x00402092, 0x0361032a, 0xfe105d7e, 0x00593877, 0x0013ff88, 0xfff989ef, - 0x2eafeeed, 0xf109be56, 0x00689598, 0x034ee39b, 0xfe123db6, 0x005b5267, 0x0012edea, 0xfff9b85b, - 0x2dfcd873, 0xf0efe748, 0x0090911f, 0x033caf1d, 0xfe144570, 0x005d59c6, 0x0011e06d, 0xfff9e65a, - 0x2d498ad3, 0xf0d7a622, 0x00b81102, 0x032a6796, 0xfe1673f2, 0x005f4eac, 0x0010d71d, 0xfffa13e5, - 0x2c960ea3, 0xf0c0f808, 0x00df1328, 0x03180ee7, 0xfe18c884, 0x0061312e, 0x000fd205, 0xfffa40f8, - 0x2be26c73, 0xf0abda0e, 0x0105958c, 0x0305a6f0, 0xfe1b4268, 0x00630167, 0x000ed130, 0xfffa6d8d, - 0x2b2eaccf, 0xf0984931, 0x012b9635, 0x02f3318a, 0xfe1de0e2, 0x0064bf71, 0x000dd4a7, 0xfffa999d, - 0x2a7ad83c, 0xf086425a, 0x0151133e, 0x02e0b08d, 0xfe20a335, 0x00666b68, 0x000cdc74, 0xfffac525, - 0x29c6f738, 0xf075c260, 0x01760ad1, 0x02ce25ca, 0xfe2388a1, 0x0068056b, 0x000be89f, 0xfffaf01e, - 0x2913123c, 0xf066c606, 0x019a7b27, 0x02bb9310, 0xfe269065, 0x00698d98, 0x000af931, 0xfffb1a84, - 0x285f31b7, 0xf05949fb, 0x01be628c, 0x02a8fa2a, 0xfe29b9c1, 0x006b0411, 0x000a0e2f, 0xfffb4453, - 0x27ab5e12, 0xf04d4ade, 0x01e1bf58, 0x02965cdb, 0xfe2d03f2, 0x006c68f8, 0x000927a0, 0xfffb6d86, - 0x26f79fab, 0xf042c539, 0x02048ff8, 0x0283bce6, 0xfe306e35, 0x006dbc71, 0x00084589, 0xfffb961a, - 0x2643feda, 0xf039b587, 0x0226d2e6, 0x02711c05, 0xfe33f7c7, 0x006efea0, 0x000767f0, 0xfffbbe09, - 0x259083eb, 0xf032182f, 0x024886ad, 0x025e7bf0, 0xfe379fe3, 0x00702fae, 0x00068ed8, 0xfffbe552, - 0x24dd3721, 0xf02be98a, 0x0269a9e9, 0x024bde5a, 0xfe3b65c4, 0x00714fc0, 0x0005ba46, 0xfffc0bef, - 0x242a20b3, 0xf02725dc, 0x028a3b44, 0x023944ee, 0xfe3f48a5, 0x00725f02, 0x0004ea3a, 0xfffc31df, - 0x237748cf, 0xf023c95d, 0x02aa397b, 0x0226b156, 0xfe4347c0, 0x00735d9c, 0x00041eb9, 0xfffc571e, - 0x22c4b795, 0xf021d031, 0x02c9a359, 0x02142533, 0xfe476250, 0x00744bba, 0x000357c2, 0xfffc7ba9, - 0x2212751a, 0xf0213671, 0x02e877b9, 0x0201a223, 0xfe4b978e, 0x0075298a, 0x00029558, 0xfffc9f7e, - 0x21608968, 0xf021f823, 0x0306b586, 0x01ef29be, 0xfe4fe6b3, 0x0075f739, 0x0001d779, 0xfffcc29a, - 0x20aefc79, 0xf0241140, 0x03245bbc, 0x01dcbd96, 0xfe544efb, 0x0076b4f5, 0x00011e26, 0xfffce4fc, - 0x1ffdd63b, 0xf0277db1, 0x03416966, 0x01ca5f37, 0xfe58cf9d, 0x007762f0, 0x0000695e, 0xfffd06a1, - 0x1f4d1e8e, 0xf02c3953, 0x035ddd9e, 0x01b81028, 0xfe5d67d4, 0x0078015a, 0xffffb91f, 0xfffd2787, - 0x1e9cdd43, 0xf0323ff5, 0x0379b790, 0x01a5d1ea, 0xfe6216db, 0x00789065, 0xffff0d66, 0xfffd47ae, - 0x1ded1a1d, 0xf0398d56, 0x0394f674, 0x0193a5f9, 0xfe66dbeb, 0x00791043, 0xfffe6631, 0xfffd6713, +#include "AudioResamplerSincDown.h" }; // we use 15 bits to interpolate between these samples @@ -521,7 +265,8 @@ void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount, if (mConstants == &veryHighQualityConstants && readResampleCoefficients) { mFirCoefs = readResampleCoefficients( mInSampleRate <= mSampleRate ); } else { - mFirCoefs = (const int32_t *) ((mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown); + mFirCoefs = (const int32_t *) + ((mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown); } // select the appropriate resampler @@ -856,4 +601,4 @@ void AudioResamplerSinc::interpolate( } } // ---------------------------------------------------------------------------- -}; // namespace android +} // namespace android diff --git a/services/audioflinger/AudioResamplerSinc.h b/services/audioflinger/AudioResamplerSinc.h index 4691d0a..6d8e85d 100644 --- a/services/audioflinger/AudioResamplerSinc.h +++ b/services/audioflinger/AudioResamplerSinc.h @@ -95,6 +95,6 @@ private: }; // ---------------------------------------------------------------------------- -}; // namespace android +} // namespace android #endif /*ANDROID_AUDIO_RESAMPLER_SINC_H*/ diff --git a/services/audioflinger/AudioResamplerSincDown.h b/services/audioflinger/AudioResamplerSincDown.h new file mode 100644 index 0000000..2d0fb86 --- /dev/null +++ b/services/audioflinger/AudioResamplerSincDown.h @@ -0,0 +1,131 @@ +// cmd-line: fir -l 7 -s48000 -c 17189 + + 0x5bacb6f4, 0x1ded1a1d, 0xf0398d56, 0x0394f674, 0x0193a5f9, 0xfe66dbeb, 0x00791043, 0xfffe6631, + 0x5bab6c81, 0x1d3ddccd, 0xf0421d2c, 0x03af9995, 0x01818dc9, 0xfe6bb63e, 0x0079812a, 0xfffdc37d, + 0x5ba78d37, 0x1c8f2cf9, 0xf04beb1d, 0x03c9a04a, 0x016f8aca, 0xfe70a511, 0x0079e34d, 0xfffd2545, + 0x5ba1194f, 0x1be11231, 0xf056f2c7, 0x03e309fe, 0x015d9e64, 0xfe75a79f, 0x007a36e2, 0xfffc8b86, + 0x5b981122, 0x1b3393f8, 0xf0632fb7, 0x03fbd625, 0x014bc9fa, 0xfe7abd23, 0x007a7c20, 0xfffbf639, + 0x5b8c7530, 0x1a86b9bf, 0xf0709d74, 0x04140449, 0x013a0ee9, 0xfe7fe4db, 0x007ab33d, 0xfffb655b, + 0x5b7e461a, 0x19da8ae5, 0xf07f3776, 0x042b93fd, 0x01286e86, 0xfe851e05, 0x007adc72, 0xfffad8e4, + 0x5b6d84a8, 0x192f0eb7, 0xf08ef92d, 0x044284e6, 0x0116ea22, 0xfe8a67dd, 0x007af7f6, 0xfffa50ce, + 0x5b5a31c6, 0x18844c70, 0xf09fddfe, 0x0458d6b7, 0x01058306, 0xfe8fc1a5, 0x007b0603, 0xfff9cd12, + 0x5b444e81, 0x17da4b37, 0xf0b1e143, 0x046e8933, 0x00f43a74, 0xfe952a9b, 0x007b06d4, 0xfff94da9, + 0x5b2bdc0e, 0x17311222, 0xf0c4fe50, 0x04839c29, 0x00e311a9, 0xfe9aa201, 0x007afaa1, 0xfff8d28c, + 0x5b10dbc2, 0x1688a832, 0xf0d9306d, 0x04980f79, 0x00d209db, 0xfea02719, 0x007ae1a7, 0xfff85bb1, + 0x5af34f18, 0x15e11453, 0xf0ee72db, 0x04abe310, 0x00c12439, 0xfea5b926, 0x007abc20, 0xfff7e910, + 0x5ad337af, 0x153a5d5e, 0xf104c0d2, 0x04bf16e9, 0x00b061eb, 0xfeab576d, 0x007a8a49, 0xfff77a9f, + 0x5ab09748, 0x14948a16, 0xf11c1583, 0x04d1ab0d, 0x009fc413, 0xfeb10134, 0x007a4c5d, 0xfff71057, + 0x5a8b6fc7, 0x13efa12c, 0xf1346c17, 0x04e39f93, 0x008f4bcb, 0xfeb6b5c0, 0x007a029a, 0xfff6aa2b, + 0x5a63c336, 0x134ba937, 0xf14dbfb1, 0x04f4f4a2, 0x007efa29, 0xfebc745c, 0x0079ad3d, 0xfff64812, + 0x5a3993c0, 0x12a8a8bb, 0xf1680b6e, 0x0505aa6a, 0x006ed038, 0xfec23c50, 0x00794c82, 0xfff5ea02, + 0x5a0ce3b2, 0x1206a625, 0xf1834a63, 0x0515c12d, 0x005ecf01, 0xfec80ce8, 0x0078e0a9, 0xfff58ff0, + 0x59ddb57f, 0x1165a7cc, 0xf19f77a0, 0x05253938, 0x004ef782, 0xfecde571, 0x007869ee, 0xfff539cf, + 0x59ac0bba, 0x10c5b3ef, 0xf1bc8e31, 0x053412e4, 0x003f4ab4, 0xfed3c538, 0x0077e891, 0xfff4e794, + 0x5977e919, 0x1026d0b8, 0xf1da891b, 0x05424e9b, 0x002fc98a, 0xfed9ab8f, 0x00775ccf, 0xfff49934, + 0x59415075, 0x0f890437, 0xf1f96360, 0x054feccf, 0x002074ed, 0xfedf97c6, 0x0076c6e8, 0xfff44ea3, + 0x590844c9, 0x0eec5465, 0xf21917ff, 0x055cee03, 0x00114dc3, 0xfee58932, 0x00762719, 0xfff407d2, + 0x58ccc930, 0x0e50c723, 0xf239a1ef, 0x056952c3, 0x000254e8, 0xfeeb7f27, 0x00757da3, 0xfff3c4b7, + 0x588ee0ea, 0x0db6623b, 0xf25afc29, 0x05751baa, 0xfff38b32, 0xfef178fc, 0x0074cac4, 0xfff38542, + 0x584e8f56, 0x0d1d2b5d, 0xf27d219f, 0x0580495c, 0xffe4f171, 0xfef7760c, 0x00740ebb, 0xfff34968, + 0x580bd7f4, 0x0c85281f, 0xf2a00d43, 0x058adc8d, 0xffd6886d, 0xfefd75af, 0x007349c7, 0xfff3111b, + 0x57c6be67, 0x0bee5dff, 0xf2c3ba04, 0x0594d5fa, 0xffc850e6, 0xff037744, 0x00727c27, 0xfff2dc4c, + 0x577f4670, 0x0b58d262, 0xf2e822ce, 0x059e366c, 0xffba4b98, 0xff097a29, 0x0071a61b, 0xfff2aaef, + 0x573573f2, 0x0ac48a92, 0xf30d428e, 0x05a6feb9, 0xffac7936, 0xff0f7dbf, 0x0070c7e1, 0xfff27cf3, + 0x56e94af1, 0x0a318bc1, 0xf333142f, 0x05af2fbf, 0xff9eda6d, 0xff15816a, 0x006fe1b8, 0xfff2524c, + 0x569acf90, 0x099fdb04, 0xf359929a, 0x05b6ca6b, 0xff916fe1, 0xff1b848e, 0x006ef3df, 0xfff22aea, + 0x564a0610, 0x090f7d57, 0xf380b8ba, 0x05bdcfb2, 0xff843a32, 0xff218692, 0x006dfe94, 0xfff206bf, + 0x55f6f2d3, 0x0880779d, 0xf3a88179, 0x05c44095, 0xff7739f7, 0xff2786e1, 0x006d0217, 0xfff1e5bb, + 0x55a19a5c, 0x07f2ce9b, 0xf3d0e7c2, 0x05ca1e1f, 0xff6a6fc1, 0xff2d84e5, 0x006bfea4, 0xfff1c7d0, + 0x554a0148, 0x076686fc, 0xf3f9e680, 0x05cf6965, 0xff5ddc1a, 0xff33800e, 0x006af47b, 0xfff1acef, + 0x54f02c56, 0x06dba551, 0xf42378a0, 0x05d42387, 0xff517f86, 0xff3977cb, 0x0069e3d9, 0xfff19508, + 0x54942061, 0x06522e0f, 0xf44d9912, 0x05d84daf, 0xff455a80, 0xff3f6b8f, 0x0068ccfa, 0xfff1800b, + 0x5435e263, 0x05ca258f, 0xf47842c5, 0x05dbe90f, 0xff396d7f, 0xff455acf, 0x0067b01e, 0xfff16de9, + 0x53d57774, 0x0543900d, 0xf4a370ad, 0x05def6e4, 0xff2db8f2, 0xff4b4503, 0x00668d80, 0xfff15e93, + 0x5372e4c6, 0x04be71ab, 0xf4cf1dbf, 0x05e17873, 0xff223d40, 0xff5129a3, 0x0065655d, 0xfff151f9, + 0x530e2fac, 0x043ace6e, 0xf4fb44f4, 0x05e36f0d, 0xff16faca, 0xff57082e, 0x006437f1, 0xfff1480b, + 0x52a75d90, 0x03b8aa40, 0xf527e149, 0x05e4dc08, 0xff0bf1ed, 0xff5ce021, 0x00630577, 0xfff140b9, + 0x523e73fd, 0x033808eb, 0xf554edbd, 0x05e5c0c6, 0xff0122fc, 0xff62b0fd, 0x0061ce2c, 0xfff13bf3, + 0x51d37897, 0x02b8ee22, 0xf5826555, 0x05e61eae, 0xfef68e45, 0xff687a47, 0x00609249, 0xfff139aa, + 0x5166711c, 0x023b5d76, 0xf5b0431a, 0x05e5f733, 0xfeec340f, 0xff6e3b84, 0x005f520a, 0xfff139cd, + 0x50f76368, 0x01bf5a5e, 0xf5de8218, 0x05e54bcd, 0xfee2149b, 0xff73f43d, 0x005e0da8, 0xfff13c4c, + 0x5086556f, 0x0144e834, 0xf60d1d63, 0x05e41dfe, 0xfed83023, 0xff79a3fe, 0x005cc55c, 0xfff14119, + 0x50134d3e, 0x00cc0a36, 0xf63c1012, 0x05e26f4e, 0xfece86db, 0xff7f4a54, 0x005b7961, 0xfff14821, + 0x4f9e50ff, 0x0054c382, 0xf66b5544, 0x05e0414d, 0xfec518f1, 0xff84e6d0, 0x005a29ed, 0xfff15156, + 0x4f2766f2, 0xffdf171b, 0xf69ae81d, 0x05dd9593, 0xfebbe68c, 0xff8a7905, 0x0058d738, 0xfff15ca8, + 0x4eae9571, 0xff6b07e7, 0xf6cac3c7, 0x05da6dbe, 0xfeb2efcd, 0xff900089, 0x0057817b, 0xfff16a07, + 0x4e33e2ee, 0xfef898ae, 0xf6fae373, 0x05d6cb72, 0xfeaa34d0, 0xff957cf4, 0x005628ec, 0xfff17962, + 0x4db755f3, 0xfe87cc1b, 0xf72b425b, 0x05d2b05c, 0xfea1b5a9, 0xff9aede0, 0x0054cdc0, 0xfff18aab, + 0x4d38f520, 0xfe18a4bc, 0xf75bdbbd, 0x05ce1e2d, 0xfe997268, 0xffa052ec, 0x0053702d, 0xfff19dd1, + 0x4cb8c72e, 0xfdab2501, 0xf78caae0, 0x05c9169d, 0xfe916b15, 0xffa5abb8, 0x00521068, 0xfff1b2c5, + 0x4c36d2eb, 0xfd3f4f3d, 0xf7bdab16, 0x05c39b6a, 0xfe899fb2, 0xffaaf7e6, 0x0050aea5, 0xfff1c976, + 0x4bb31f3c, 0xfcd525a5, 0xf7eed7b4, 0x05bdae57, 0xfe82103f, 0xffb0371c, 0x004f4b17, 0xfff1e1d6, + 0x4b2db31a, 0xfc6caa53, 0xf8202c1c, 0x05b7512e, 0xfe7abcb1, 0xffb56902, 0x004de5f1, 0xfff1fbd5, + 0x4aa69594, 0xfc05df40, 0xf851a3b6, 0x05b085bc, 0xfe73a4fb, 0xffba8d44, 0x004c7f66, 0xfff21764, + 0x4a1dcdce, 0xfba0c64b, 0xf88339f5, 0x05a94dd5, 0xfe6cc909, 0xffbfa38d, 0x004b17a6, 0xfff23473, + 0x499362ff, 0xfb3d6133, 0xf8b4ea55, 0x05a1ab52, 0xfe6628c1, 0xffc4ab8f, 0x0049aee3, 0xfff252f3, + 0x49075c72, 0xfadbb19a, 0xf8e6b059, 0x0599a00e, 0xfe5fc405, 0xffc9a4fc, 0x0048454b, 0xfff272d6, + 0x4879c185, 0xfa7bb908, 0xf9188793, 0x05912dea, 0xfe599aaf, 0xffce8f8a, 0x0046db0f, 0xfff2940b, + 0x47ea99a9, 0xfa1d78e3, 0xf94a6b9b, 0x058856cd, 0xfe53ac97, 0xffd36af1, 0x0045705c, 0xfff2b686, + 0x4759ec60, 0xf9c0f276, 0xf97c5815, 0x057f1c9e, 0xfe4df98e, 0xffd836eb, 0x00440561, 0xfff2da36, + 0x46c7c140, 0xf96626f0, 0xf9ae48af, 0x0575814c, 0xfe48815e, 0xffdcf336, 0x00429a4a, 0xfff2ff0d, + 0x46341fed, 0xf90d1761, 0xf9e03924, 0x056b86c6, 0xfe4343d0, 0xffe19f91, 0x00412f43, 0xfff324fd, + 0x459f101d, 0xf8b5c4be, 0xfa122537, 0x05612f00, 0xfe3e40a6, 0xffe63bc0, 0x003fc478, 0xfff34bf9, + 0x45089996, 0xf8602fdc, 0xfa4408ba, 0x05567bf1, 0xfe39779a, 0xffeac787, 0x003e5a12, 0xfff373f0, + 0x4470c42d, 0xf80c5977, 0xfa75df87, 0x054b6f92, 0xfe34e867, 0xffef42af, 0x003cf03d, 0xfff39cd7, + 0x43d797c7, 0xf7ba422b, 0xfaa7a586, 0x05400be1, 0xfe3092bf, 0xfff3ad01, 0x003b871f, 0xfff3c69f, + 0x433d1c56, 0xf769ea78, 0xfad956ab, 0x053452dc, 0xfe2c7650, 0xfff8064b, 0x003a1ee3, 0xfff3f13a, + 0x42a159dc, 0xf71b52c4, 0xfb0aeef6, 0x05284685, 0xfe2892c5, 0xfffc4e5c, 0x0038b7ae, 0xfff41c9c, + 0x42045865, 0xf6ce7b57, 0xfb3c6a73, 0x051be8dd, 0xfe24e7c3, 0x00008507, 0x003751a7, 0xfff448b7, + 0x4166200e, 0xf683645a, 0xfb6dc53c, 0x050f3bec, 0xfe2174ec, 0x0004aa1f, 0x0035ecf4, 0xfff4757e, + 0x40c6b8fd, 0xf63a0ddf, 0xfb9efb77, 0x050241b6, 0xfe1e39da, 0x0008bd7c, 0x003489b9, 0xfff4a2e5, + 0x40262b65, 0xf5f277d9, 0xfbd00956, 0x04f4fc46, 0xfe1b3628, 0x000cbef7, 0x0033281a, 0xfff4d0de, + 0x3f847f83, 0xf5aca21f, 0xfc00eb1b, 0x04e76da3, 0xfe18696a, 0x0010ae6e, 0x0031c83a, 0xfff4ff5d, + 0x3ee1bda2, 0xf5688c6d, 0xfc319d13, 0x04d997d8, 0xfe15d32f, 0x00148bbd, 0x00306a3b, 0xfff52e57, + 0x3e3dee13, 0xf5263665, 0xfc621b9a, 0x04cb7cf2, 0xfe137304, 0x001856c7, 0x002f0e3f, 0xfff55dbf, + 0x3d991932, 0xf4e59f8a, 0xfc926319, 0x04bd1efb, 0xfe114872, 0x001c0f6e, 0x002db466, 0xfff58d89, + 0x3cf34766, 0xf4a6c748, 0xfcc27008, 0x04ae8000, 0xfe0f52fc, 0x001fb599, 0x002c5cd0, 0xfff5bdaa, + 0x3c4c811c, 0xf469aced, 0xfcf23eec, 0x049fa20f, 0xfe0d9224, 0x0023492f, 0x002b079a, 0xfff5ee17, + 0x3ba4cec9, 0xf42e4faf, 0xfd21cc59, 0x04908733, 0xfe0c0567, 0x0026ca1c, 0x0029b4e4, 0xfff61ec5, + 0x3afc38eb, 0xf3f4aea6, 0xfd5114f0, 0x0481317a, 0xfe0aac3f, 0x002a384c, 0x002864c9, 0xfff64fa8, + 0x3a52c805, 0xf3bcc8d3, 0xfd801564, 0x0471a2ef, 0xfe098622, 0x002d93ae, 0x00271766, 0xfff680b5, + 0x39a884a1, 0xf3869d1a, 0xfdaeca73, 0x0461dda0, 0xfe089283, 0x0030dc34, 0x0025ccd7, 0xfff6b1e4, + 0x38fd774e, 0xf3522a49, 0xfddd30eb, 0x0451e396, 0xfe07d0d3, 0x003411d2, 0x00248535, 0xfff6e329, + 0x3851a8a2, 0xf31f6f0f, 0xfe0b45aa, 0x0441b6dd, 0xfe07407d, 0x0037347d, 0x0023409a, 0xfff7147a, + 0x37a52135, 0xf2ee6a07, 0xfe39059b, 0x0431597d, 0xfe06e0eb, 0x003a442e, 0x0021ff1f, 0xfff745cd, + 0x36f7e9a4, 0xf2bf19ae, 0xfe666dbc, 0x0420cd80, 0xfe06b184, 0x003d40e0, 0x0020c0dc, 0xfff7771a, + 0x364a0a90, 0xf2917c6d, 0xfe937b15, 0x041014eb, 0xfe06b1ac, 0x00402a8e, 0x001f85e6, 0xfff7a857, + 0x359b8c9d, 0xf265908f, 0xfec02ac2, 0x03ff31c3, 0xfe06e0c4, 0x00430137, 0x001e4e56, 0xfff7d97a, + 0x34ec786f, 0xf23b544b, 0xfeec79ec, 0x03ee260d, 0xfe073e2a, 0x0045c4dd, 0x001d1a3f, 0xfff80a7c, + 0x343cd6af, 0xf212c5be, 0xff1865cd, 0x03dcf3ca, 0xfe07c93a, 0x00487582, 0x001be9b7, 0xfff83b52, + 0x338cb004, 0xf1ebe2ec, 0xff43ebac, 0x03cb9cf9, 0xfe08814e, 0x004b132b, 0x001abcd0, 0xfff86bf6, + 0x32dc0d17, 0xf1c6a9c3, 0xff6f08e4, 0x03ba2398, 0xfe0965bc, 0x004d9dde, 0x0019939d, 0xfff89c60, + 0x322af693, 0xf1a3181a, 0xff99badb, 0x03a889a1, 0xfe0a75da, 0x005015a5, 0x00186e31, 0xfff8cc86, + 0x3179751f, 0xf1812bb0, 0xffc3ff0c, 0x0396d10c, 0xfe0bb0f9, 0x00527a8a, 0x00174c9c, 0xfff8fc62, + 0x30c79163, 0xf160e22d, 0xffedd2fd, 0x0384fbd1, 0xfe0d166b, 0x0054cc9a, 0x00162eef, 0xfff92bec, + 0x30155404, 0xf1423924, 0x00173447, 0x03730be0, 0xfe0ea57e, 0x00570be4, 0x00151538, 0xfff95b1e, + 0x2f62c5a7, 0xf1252e0f, 0x00402092, 0x0361032a, 0xfe105d7e, 0x00593877, 0x0013ff88, 0xfff989ef, + 0x2eafeeed, 0xf109be56, 0x00689598, 0x034ee39b, 0xfe123db6, 0x005b5267, 0x0012edea, 0xfff9b85b, + 0x2dfcd873, 0xf0efe748, 0x0090911f, 0x033caf1d, 0xfe144570, 0x005d59c6, 0x0011e06d, 0xfff9e65a, + 0x2d498ad3, 0xf0d7a622, 0x00b81102, 0x032a6796, 0xfe1673f2, 0x005f4eac, 0x0010d71d, 0xfffa13e5, + 0x2c960ea3, 0xf0c0f808, 0x00df1328, 0x03180ee7, 0xfe18c884, 0x0061312e, 0x000fd205, 0xfffa40f8, + 0x2be26c73, 0xf0abda0e, 0x0105958c, 0x0305a6f0, 0xfe1b4268, 0x00630167, 0x000ed130, 0xfffa6d8d, + 0x2b2eaccf, 0xf0984931, 0x012b9635, 0x02f3318a, 0xfe1de0e2, 0x0064bf71, 0x000dd4a7, 0xfffa999d, + 0x2a7ad83c, 0xf086425a, 0x0151133e, 0x02e0b08d, 0xfe20a335, 0x00666b68, 0x000cdc74, 0xfffac525, + 0x29c6f738, 0xf075c260, 0x01760ad1, 0x02ce25ca, 0xfe2388a1, 0x0068056b, 0x000be89f, 0xfffaf01e, + 0x2913123c, 0xf066c606, 0x019a7b27, 0x02bb9310, 0xfe269065, 0x00698d98, 0x000af931, 0xfffb1a84, + 0x285f31b7, 0xf05949fb, 0x01be628c, 0x02a8fa2a, 0xfe29b9c1, 0x006b0411, 0x000a0e2f, 0xfffb4453, + 0x27ab5e12, 0xf04d4ade, 0x01e1bf58, 0x02965cdb, 0xfe2d03f2, 0x006c68f8, 0x000927a0, 0xfffb6d86, + 0x26f79fab, 0xf042c539, 0x02048ff8, 0x0283bce6, 0xfe306e35, 0x006dbc71, 0x00084589, 0xfffb961a, + 0x2643feda, 0xf039b587, 0x0226d2e6, 0x02711c05, 0xfe33f7c7, 0x006efea0, 0x000767f0, 0xfffbbe09, + 0x259083eb, 0xf032182f, 0x024886ad, 0x025e7bf0, 0xfe379fe3, 0x00702fae, 0x00068ed8, 0xfffbe552, + 0x24dd3721, 0xf02be98a, 0x0269a9e9, 0x024bde5a, 0xfe3b65c4, 0x00714fc0, 0x0005ba46, 0xfffc0bef, + 0x242a20b3, 0xf02725dc, 0x028a3b44, 0x023944ee, 0xfe3f48a5, 0x00725f02, 0x0004ea3a, 0xfffc31df, + 0x237748cf, 0xf023c95d, 0x02aa397b, 0x0226b156, 0xfe4347c0, 0x00735d9c, 0x00041eb9, 0xfffc571e, + 0x22c4b795, 0xf021d031, 0x02c9a359, 0x02142533, 0xfe476250, 0x00744bba, 0x000357c2, 0xfffc7ba9, + 0x2212751a, 0xf0213671, 0x02e877b9, 0x0201a223, 0xfe4b978e, 0x0075298a, 0x00029558, 0xfffc9f7e, + 0x21608968, 0xf021f823, 0x0306b586, 0x01ef29be, 0xfe4fe6b3, 0x0075f739, 0x0001d779, 0xfffcc29a, + 0x20aefc79, 0xf0241140, 0x03245bbc, 0x01dcbd96, 0xfe544efb, 0x0076b4f5, 0x00011e26, 0xfffce4fc, + 0x1ffdd63b, 0xf0277db1, 0x03416966, 0x01ca5f37, 0xfe58cf9d, 0x007762f0, 0x0000695e, 0xfffd06a1, + 0x1f4d1e8e, 0xf02c3953, 0x035ddd9e, 0x01b81028, 0xfe5d67d4, 0x0078015a, 0xffffb91f, 0xfffd2787, + 0x1e9cdd43, 0xf0323ff5, 0x0379b790, 0x01a5d1ea, 0xfe6216db, 0x00789065, 0xffff0d66, 0xfffd47ae, + 0x1ded1a1d, 0xf0398d56, 0x0394f674, 0x0193a5f9, 0xfe66dbeb, 0x00791043, 0xfffe6631, 0xfffd6713, diff --git a/services/audioflinger/AudioResamplerSincUp.h b/services/audioflinger/AudioResamplerSincUp.h new file mode 100644 index 0000000..fd5367e --- /dev/null +++ b/services/audioflinger/AudioResamplerSincUp.h @@ -0,0 +1,131 @@ +// cmd-line: fir -l 7 -s48000 -c 20478 + + 0x6d374bc7, 0x111c6ba0, 0xf3240e61, 0x07d14a38, 0xfc509e64, 0x0139cee9, 0xffc8c866, 0xfffcc300, + 0x6d35278a, 0x103e8192, 0xf36b9dfd, 0x07bdfaa5, 0xfc5102d0, 0x013d618d, 0xffc663b9, 0xfffd9592, + 0x6d2ebafe, 0x0f62811a, 0xf3b3d8ac, 0x07a9f399, 0xfc51d9a6, 0x0140bea5, 0xffc41212, 0xfffe631e, + 0x6d24069d, 0x0e8875ad, 0xf3fcb43e, 0x07953976, 0xfc53216f, 0x0143e67c, 0xffc1d373, 0xffff2b9f, + 0x6d150b35, 0x0db06a89, 0xf4462690, 0x077fd0ac, 0xfc54d8ae, 0x0146d965, 0xffbfa7d9, 0xffffef10, + 0x6d01c9e3, 0x0cda6ab5, 0xf4902587, 0x0769bdaf, 0xfc56fdda, 0x014997bb, 0xffbd8f40, 0x0000ad6e, + 0x6cea4418, 0x0c0680fe, 0xf4daa718, 0x07530501, 0xfc598f60, 0x014c21db, 0xffbb89a1, 0x000166b6, + 0x6cce7b97, 0x0b34b7f5, 0xf525a143, 0x073bab28, 0xfc5c8ba5, 0x014e782a, 0xffb996f3, 0x00021ae5, + 0x6cae7272, 0x0a6519f4, 0xf5710a17, 0x0723b4b4, 0xfc5ff105, 0x01509b14, 0xffb7b728, 0x0002c9fd, + 0x6c8a2b0f, 0x0997b116, 0xf5bcd7b1, 0x070b2639, 0xfc63bdd3, 0x01528b08, 0xffb5ea31, 0x000373fb, + 0x6c61a823, 0x08cc873c, 0xf609003f, 0x06f20453, 0xfc67f05a, 0x0154487b, 0xffb42ffc, 0x000418e2, + 0x6c34ecb5, 0x0803a60a, 0xf6557a00, 0x06d853a2, 0xfc6c86dd, 0x0155d3e8, 0xffb28876, 0x0004b8b3, + 0x6c03fc1c, 0x073d16e7, 0xf6a23b44, 0x06be18cd, 0xfc717f97, 0x01572dcf, 0xffb0f388, 0x00055371, + 0x6bced9ff, 0x0678e2fc, 0xf6ef3a6e, 0x06a3587e, 0xfc76d8bc, 0x015856b6, 0xffaf7118, 0x0005e921, + 0x6b958a54, 0x05b71332, 0xf73c6df4, 0x06881761, 0xfc7c9079, 0x01594f25, 0xffae010b, 0x000679c5, + 0x6b581163, 0x04f7b037, 0xf789cc61, 0x066c5a27, 0xfc82a4f4, 0x015a17ab, 0xffaca344, 0x00070564, + 0x6b1673c1, 0x043ac276, 0xf7d74c53, 0x06502583, 0xfc89144d, 0x015ab0db, 0xffab57a1, 0x00078c04, + 0x6ad0b652, 0x0380521c, 0xf824e480, 0x06337e2a, 0xfc8fdc9f, 0x015b1b4e, 0xffaa1e02, 0x00080dab, + 0x6a86de48, 0x02c86715, 0xf8728bb3, 0x061668d2, 0xfc96fbfc, 0x015b579e, 0xffa8f641, 0x00088a62, + 0x6a38f123, 0x0213090c, 0xf8c038d0, 0x05f8ea30, 0xfc9e7074, 0x015b666c, 0xffa7e039, 0x00090230, + 0x69e6f4b1, 0x01603f6e, 0xf90de2d1, 0x05db06fc, 0xfca63810, 0x015b485b, 0xffa6dbc0, 0x0009751e, + 0x6990ef0b, 0x00b01162, 0xf95b80cb, 0x05bcc3ed, 0xfcae50d6, 0x015afe14, 0xffa5e8ad, 0x0009e337, + 0x6936e697, 0x000285d0, 0xf9a909ea, 0x059e25b5, 0xfcb6b8c4, 0x015a8843, 0xffa506d2, 0x000a4c85, + 0x68d8e206, 0xff57a35e, 0xf9f67577, 0x057f310a, 0xfcbf6dd8, 0x0159e796, 0xffa43603, 0x000ab112, + 0x6876e855, 0xfeaf706f, 0xfa43bad2, 0x055fea9d, 0xfcc86e09, 0x01591cc0, 0xffa3760e, 0x000b10ec, + 0x681100c9, 0xfe09f323, 0xfa90d17b, 0x0540571a, 0xfcd1b74c, 0x01582878, 0xffa2c6c2, 0x000b6c1d, + 0x67a732f4, 0xfd673159, 0xfaddb10c, 0x05207b2f, 0xfcdb4793, 0x01570b77, 0xffa227ec, 0x000bc2b3, + 0x673986ac, 0xfcc730aa, 0xfb2a513b, 0x05005b82, 0xfce51ccb, 0x0155c678, 0xffa19957, 0x000c14bb, + 0x66c80413, 0xfc29f670, 0xfb76a9dd, 0x04dffcb6, 0xfcef34e1, 0x01545a3c, 0xffa11acb, 0x000c6244, + 0x6652b392, 0xfb8f87bd, 0xfbc2b2e4, 0x04bf6369, 0xfcf98dbe, 0x0152c783, 0xffa0ac11, 0x000cab5c, + 0x65d99dd5, 0xfaf7e963, 0xfc0e6461, 0x049e9433, 0xfd04254a, 0x01510f13, 0xffa04cf0, 0x000cf012, + 0x655ccbd3, 0xfa631fef, 0xfc59b685, 0x047d93a8, 0xfd0ef969, 0x014f31b2, 0xff9ffd2c, 0x000d3075, + 0x64dc46c3, 0xf9d12fab, 0xfca4a19f, 0x045c6654, 0xfd1a0801, 0x014d3029, 0xff9fbc89, 0x000d6c97, + 0x64581823, 0xf9421c9d, 0xfcef1e20, 0x043b10bd, 0xfd254ef4, 0x014b0b45, 0xff9f8ac9, 0x000da486, + 0x63d049b4, 0xf8b5ea87, 0xfd392498, 0x04199760, 0xfd30cc24, 0x0148c3d2, 0xff9f67ae, 0x000dd854, + 0x6344e578, 0xf82c9ce7, 0xfd82adba, 0x03f7feb4, 0xfd3c7d73, 0x01465a9f, 0xff9f52f7, 0x000e0812, + 0x62b5f5b2, 0xf7a636fa, 0xfdcbb25a, 0x03d64b27, 0xfd4860c2, 0x0143d07f, 0xff9f4c65, 0x000e33d3, + 0x622384e8, 0xf722bbb5, 0xfe142b6e, 0x03b4811d, 0xfd5473f3, 0x01412643, 0xff9f53b4, 0x000e5ba7, + 0x618d9ddc, 0xf6a22dcf, 0xfe5c120f, 0x0392a4f4, 0xfd60b4e7, 0x013e5cc0, 0xff9f68a1, 0x000e7fa1, + 0x60f44b91, 0xf6248fb6, 0xfea35f79, 0x0370bafc, 0xfd6d2180, 0x013b74ca, 0xff9f8ae9, 0x000e9fd5, + 0x60579947, 0xf5a9e398, 0xfeea0d0c, 0x034ec77f, 0xfd79b7a1, 0x01386f3a, 0xff9fba47, 0x000ebc54, + 0x5fb79278, 0xf5322b61, 0xff30144a, 0x032ccebb, 0xfd86752e, 0x01354ce7, 0xff9ff674, 0x000ed533, + 0x5f1442dc, 0xf4bd68b6, 0xff756edc, 0x030ad4e1, 0xfd93580d, 0x01320ea9, 0xffa03f2b, 0x000eea84, + 0x5e6db665, 0xf44b9cfe, 0xffba168d, 0x02e8de19, 0xfda05e23, 0x012eb55a, 0xffa09425, 0x000efc5c, + 0x5dc3f93c, 0xf3dcc959, 0xfffe054e, 0x02c6ee7f, 0xfdad855b, 0x012b41d3, 0xffa0f519, 0x000f0ace, + 0x5d1717c4, 0xf370eea9, 0x00413536, 0x02a50a22, 0xfdbacb9e, 0x0127b4f1, 0xffa161bf, 0x000f15ef, + 0x5c671e96, 0xf3080d8c, 0x0083a081, 0x02833506, 0xfdc82edb, 0x01240f8e, 0xffa1d9cf, 0x000f1dd2, + 0x5bb41a80, 0xf2a2265e, 0x00c54190, 0x02617321, 0xfdd5ad01, 0x01205285, 0xffa25cfe, 0x000f228d, + 0x5afe1886, 0xf23f393b, 0x010612eb, 0x023fc85c, 0xfde34403, 0x011c7eb2, 0xffa2eb04, 0x000f2434, + 0x5a4525df, 0xf1df45fd, 0x01460f41, 0x021e3891, 0xfdf0f1d6, 0x011894f0, 0xffa38395, 0x000f22dc, + 0x59894ff3, 0xf1824c3e, 0x01853165, 0x01fcc78f, 0xfdfeb475, 0x0114961b, 0xffa42668, 0x000f1e99, + 0x58caa45b, 0xf1284b58, 0x01c37452, 0x01db7914, 0xfe0c89db, 0x0110830f, 0xffa4d332, 0x000f1781, + 0x580930e1, 0xf0d14267, 0x0200d32c, 0x01ba50d2, 0xfe1a7009, 0x010c5ca6, 0xffa589a6, 0x000f0da8, + 0x5745037c, 0xf07d3043, 0x023d493c, 0x0199526b, 0xfe286505, 0x010823ba, 0xffa6497c, 0x000f0125, + 0x567e2a51, 0xf02c138a, 0x0278d1f2, 0x01788170, 0xfe3666d5, 0x0103d927, 0xffa71266, 0x000ef20b, + 0x55b4b3af, 0xefddea9a, 0x02b368e6, 0x0157e166, 0xfe447389, 0x00ff7dc4, 0xffa7e41a, 0x000ee070, + 0x54e8ae13, 0xef92b393, 0x02ed09d7, 0x013775bf, 0xfe528931, 0x00fb126b, 0xffa8be4c, 0x000ecc69, + 0x541a281e, 0xef4a6c58, 0x0325b0ad, 0x011741df, 0xfe60a5e5, 0x00f697f3, 0xffa9a0b1, 0x000eb60b, + 0x5349309e, 0xef051290, 0x035d5977, 0x00f7491a, 0xfe6ec7c0, 0x00f20f32, 0xffaa8afe, 0x000e9d6b, + 0x5275d684, 0xeec2a3a3, 0x0394006a, 0x00d78eb3, 0xfe7cece2, 0x00ed78ff, 0xffab7ce7, 0x000e829e, + 0x51a028e8, 0xee831cc3, 0x03c9a1e5, 0x00b815da, 0xfe8b1373, 0x00e8d62d, 0xffac7621, 0x000e65ba, + 0x50c83704, 0xee467ae1, 0x03fe3a6f, 0x0098e1b3, 0xfe99399f, 0x00e4278f, 0xffad7662, 0x000e46d3, + 0x4fee1037, 0xee0cbab9, 0x0431c6b5, 0x0079f54c, 0xfea75d97, 0x00df6df7, 0xffae7d5f, 0x000e25fd, + 0x4f11c3fe, 0xedd5d8ca, 0x0464438c, 0x005b53a4, 0xfeb57d92, 0x00daaa34, 0xffaf8acd, 0x000e034f, + 0x4e3361f7, 0xeda1d15c, 0x0495adf2, 0x003cffa9, 0xfec397cf, 0x00d5dd16, 0xffb09e63, 0x000ddedb, + 0x4d52f9df, 0xed70a07d, 0x04c6030d, 0x001efc35, 0xfed1aa92, 0x00d10769, 0xffb1b7d8, 0x000db8b7, + 0x4c709b8e, 0xed424205, 0x04f54029, 0x00014c12, 0xfedfb425, 0x00cc29f7, 0xffb2d6e1, 0x000d90f6, + 0x4b8c56f8, 0xed16b196, 0x052362ba, 0xffe3f1f7, 0xfeedb2da, 0x00c7458a, 0xffb3fb37, 0x000d67ae, + 0x4aa63c2c, 0xecedea99, 0x0550685d, 0xffc6f08a, 0xfefba508, 0x00c25ae8, 0xffb52490, 0x000d3cf1, + 0x49be5b50, 0xecc7e845, 0x057c4ed4, 0xffaa4a5d, 0xff09890f, 0x00bd6ad7, 0xffb652a7, 0x000d10d5, + 0x48d4c4a2, 0xeca4a59b, 0x05a7140b, 0xff8e01f1, 0xff175d53, 0x00b87619, 0xffb78533, 0x000ce36b, + 0x47e98874, 0xec841d68, 0x05d0b612, 0xff7219b3, 0xff252042, 0x00b37d70, 0xffb8bbed, 0x000cb4c8, + 0x46fcb72d, 0xec664a48, 0x05f93324, 0xff5693fe, 0xff32d04f, 0x00ae8198, 0xffb9f691, 0x000c84ff, + 0x460e6148, 0xec4b26a2, 0x0620899e, 0xff3b731b, 0xff406bf8, 0x00a9834e, 0xffbb34d8, 0x000c5422, + 0x451e9750, 0xec32acb0, 0x0646b808, 0xff20b93e, 0xff4df1be, 0x00a4834c, 0xffbc767f, 0x000c2245, + 0x442d69de, 0xec1cd677, 0x066bbd0d, 0xff066889, 0xff5b602c, 0x009f8249, 0xffbdbb42, 0x000bef79, + 0x433ae99c, 0xec099dcf, 0x068f9781, 0xfeec830d, 0xff68b5d5, 0x009a80f8, 0xffbf02dd, 0x000bbbd2, + 0x4247273f, 0xebf8fc64, 0x06b2465b, 0xfed30ac5, 0xff75f153, 0x0095800c, 0xffc04d0f, 0x000b8760, + 0x41523389, 0xebeaebaf, 0x06d3c8bb, 0xfeba0199, 0xff831148, 0x00908034, 0xffc19996, 0x000b5235, + 0x405c1f43, 0xebdf6500, 0x06f41de3, 0xfea16960, 0xff90145e, 0x008b821b, 0xffc2e832, 0x000b1c64, + 0x3f64fb40, 0xebd6617b, 0x0713453d, 0xfe8943dc, 0xff9cf947, 0x0086866b, 0xffc438a3, 0x000ae5fc, + 0x3e6cd85b, 0xebcfda19, 0x07313e56, 0xfe7192bd, 0xffa9bebe, 0x00818dcb, 0xffc58aaa, 0x000aaf0f, + 0x3d73c772, 0xebcbc7a7, 0x074e08e0, 0xfe5a579d, 0xffb66386, 0x007c98de, 0xffc6de09, 0x000a77ac, + 0x3c79d968, 0xebca22cc, 0x0769a4b2, 0xfe439407, 0xffc2e669, 0x0077a845, 0xffc83285, 0x000a3fe5, + 0x3b7f1f23, 0xebcae405, 0x078411c7, 0xfe2d496f, 0xffcf463a, 0x0072bc9d, 0xffc987e0, 0x000a07c9, + 0x3a83a989, 0xebce03aa, 0x079d503b, 0xfe177937, 0xffdb81d6, 0x006dd680, 0xffcadde1, 0x0009cf67, + 0x3987897f, 0xebd379eb, 0x07b56051, 0xfe0224b0, 0xffe79820, 0x0068f687, 0xffcc344c, 0x000996ce, + 0x388acfe9, 0xebdb3ed5, 0x07cc426c, 0xfded4d13, 0xfff38806, 0x00641d44, 0xffcd8aeb, 0x00095e0e, + 0x378d8da8, 0xebe54a4f, 0x07e1f712, 0xfdd8f38b, 0xffff507b, 0x005f4b4a, 0xffcee183, 0x00092535, + 0x368fd397, 0xebf1941f, 0x07f67eec, 0xfdc5192d, 0x000af07f, 0x005a8125, 0xffd037e0, 0x0008ec50, + 0x3591b28b, 0xec0013e8, 0x0809dac3, 0xfdb1befc, 0x00166718, 0x0055bf60, 0xffd18dcc, 0x0008b36e, + 0x34933b50, 0xec10c12c, 0x081c0b84, 0xfd9ee5e7, 0x0021b355, 0x00510682, 0xffd2e311, 0x00087a9c, + 0x33947eab, 0xec23934f, 0x082d1239, 0xfd8c8ecc, 0x002cd44d, 0x004c570f, 0xffd4377d, 0x000841e8, + 0x32958d55, 0xec388194, 0x083cf010, 0xfd7aba74, 0x0037c922, 0x0047b186, 0xffd58ade, 0x0008095d, + 0x319677fa, 0xec4f8322, 0x084ba654, 0xfd696998, 0x004290fc, 0x00431666, 0xffd6dd02, 0x0007d108, + 0x30974f3b, 0xec688f02, 0x08593671, 0xfd589cdc, 0x004d2b0e, 0x003e8628, 0xffd82dba, 0x000798f5, + 0x2f9823a8, 0xec839c22, 0x0865a1f1, 0xfd4854d3, 0x00579691, 0x003a0141, 0xffd97cd6, 0x00076130, + 0x2e9905c1, 0xeca0a156, 0x0870ea7e, 0xfd3891fd, 0x0061d2ca, 0x00358824, 0xffdaca2a, 0x000729c4, + 0x2d9a05f4, 0xecbf9558, 0x087b11de, 0xfd2954c8, 0x006bdf05, 0x00311b41, 0xffdc1588, 0x0006f2bb, + 0x2c9b349e, 0xece06ecb, 0x088419f6, 0xfd1a9d91, 0x0075ba95, 0x002cbb03, 0xffdd5ec6, 0x0006bc21, + 0x2b9ca203, 0xed032439, 0x088c04c8, 0xfd0c6ca2, 0x007f64da, 0x002867d2, 0xffdea5bb, 0x000685ff, + 0x2a9e5e57, 0xed27ac16, 0x0892d470, 0xfcfec233, 0x0088dd38, 0x00242213, 0xffdfea3c, 0x0006505f, + 0x29a079b2, 0xed4dfcc2, 0x08988b2a, 0xfcf19e6b, 0x0092231e, 0x001fea27, 0xffe12c22, 0x00061b4b, + 0x28a30416, 0xed760c88, 0x089d2b4a, 0xfce50161, 0x009b3605, 0x001bc06b, 0xffe26b48, 0x0005e6cb, + 0x27a60d6a, 0xed9fd1a2, 0x08a0b740, 0xfcd8eb17, 0x00a4156b, 0x0017a53b, 0xffe3a788, 0x0005b2e8, + 0x26a9a57b, 0xedcb4237, 0x08a33196, 0xfccd5b82, 0x00acc0da, 0x001398ec, 0xffe4e0bf, 0x00057faa, + 0x25addbf9, 0xedf8545b, 0x08a49cf0, 0xfcc25285, 0x00b537e1, 0x000f9bd2, 0xffe616c8, 0x00054d1a, + 0x24b2c075, 0xee26fe17, 0x08a4fc0d, 0xfcb7cff0, 0x00bd7a1c, 0x000bae3c, 0xffe74984, 0x00051b3e, + 0x23b86263, 0xee573562, 0x08a451c0, 0xfcadd386, 0x00c5872a, 0x0007d075, 0xffe878d3, 0x0004ea1d, + 0x22bed116, 0xee88f026, 0x08a2a0f8, 0xfca45cf7, 0x00cd5eb7, 0x000402c8, 0xffe9a494, 0x0004b9c0, + 0x21c61bc0, 0xeebc2444, 0x089fecbb, 0xfc9b6be5, 0x00d50075, 0x00004579, 0xffeaccaa, 0x00048a2b, + 0x20ce516f, 0xeef0c78d, 0x089c3824, 0xfc92ffe1, 0x00dc6c1e, 0xfffc98c9, 0xffebf0fa, 0x00045b65, + 0x1fd7810f, 0xef26cfca, 0x08978666, 0xfc8b186d, 0x00e3a175, 0xfff8fcf7, 0xffed1166, 0x00042d74, + 0x1ee1b965, 0xef5e32bd, 0x0891dac8, 0xfc83b4fc, 0x00eaa045, 0xfff5723d, 0xffee2dd7, 0x0004005e, + 0x1ded0911, 0xef96e61c, 0x088b38a9, 0xfc7cd4f0, 0x00f16861, 0xfff1f8d2, 0xffef4632, 0x0003d426, + 0x1cf97e8b, 0xefd0df9a, 0x0883a378, 0xfc76779e, 0x00f7f9a3, 0xffee90eb, 0xfff05a60, 0x0003a8d2, + 0x1c072823, 0xf00c14e1, 0x087b1ebc, 0xfc709c4d, 0x00fe53ef, 0xffeb3ab8, 0xfff16a4a, 0x00037e65, + 0x1b1613ff, 0xf0487b98, 0x0871ae0d, 0xfc6b4233, 0x0104772e, 0xffe7f666, 0xfff275db, 0x000354e5, + 0x1a26501b, 0xf0860962, 0x08675516, 0xfc66687a, 0x010a6353, 0xffe4c41e, 0xfff37d00, 0x00032c54, + 0x1937ea47, 0xf0c4b3e0, 0x085c1794, 0xfc620e3d, 0x01101858, 0xffe1a408, 0xfff47fa5, 0x000304b7, + 0x184af025, 0xf10470b0, 0x084ff957, 0xfc5e328c, 0x0115963d, 0xffde9646, 0xfff57db8, 0x0002de0e, + 0x175f6f2b, 0xf1453571, 0x0842fe3d, 0xfc5ad465, 0x011add0b, 0xffdb9af8, 0xfff67729, 0x0002b85f, + 0x1675749e, 0xf186f7c0, 0x08352a35, 0xfc57f2be, 0x011fecd3, 0xffd8b23b, 0xfff76be9, 0x000293aa, + 0x158d0d95, 0xf1c9ad40, 0x0826813e, 0xfc558c7c, 0x0124c5ab, 0xffd5dc28, 0xfff85be8, 0x00026ff2, + 0x14a646f6, 0xf20d4b92, 0x08170767, 0xfc53a07b, 0x012967b1, 0xffd318d6, 0xfff9471b, 0x00024d39, + 0x13c12d73, 0xf251c85d, 0x0806c0cb, 0xfc522d88, 0x012dd30a, 0xffd06858, 0xfffa2d74, 0x00022b7f, + 0x12ddcd8f, 0xf297194d, 0x07f5b193, 0xfc513266, 0x013207e4, 0xffcdcabe, 0xfffb0ee9, 0x00020ac7, + 0x11fc3395, 0xf2dd3411, 0x07e3ddf7, 0xfc50adcc, 0x01360670, 0xffcb4014, 0xfffbeb70, 0x0001eb10, + 0x111c6ba0, 0xf3240e61, 0x07d14a38, 0xfc509e64, 0x0139cee9, 0xffc8c866, 0xfffcc300, 0x0001cc5c, diff --git a/services/audioflinger/Configuration.h b/services/audioflinger/Configuration.h index 6a8aeb1..845697a 100644 --- a/services/audioflinger/Configuration.h +++ b/services/audioflinger/Configuration.h @@ -29,9 +29,8 @@ // uncomment to display CPU load adjusted for CPU frequency //#define CPU_FREQUENCY_STATISTICS -// uncomment to enable fast mixer to take performance samples for later statistical analysis -#define FAST_MIXER_STATISTICS -// FIXME rename to FAST_THREAD_STATISTICS +// uncomment to enable fast threads to take performance samples for later statistical analysis +#define FAST_THREAD_STATISTICS // uncomment for debugging timing problems related to StateQueue::push() //#define STATE_QUEUE_DUMP diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp index bcaf8ae..8bccb47 100644 --- a/services/audioflinger/Effects.cpp +++ b/services/audioflinger/Effects.cpp @@ -1953,4 +1953,4 @@ void AudioFlinger::EffectChain::setThread(const sp<ThreadBase>& thread) } } -}; // namespace android +} // namespace android diff --git a/services/audioflinger/FastCapture.cpp b/services/audioflinger/FastCapture.cpp index 0c9b976..9e7e8a4 100644 --- a/services/audioflinger/FastCapture.cpp +++ b/services/audioflinger/FastCapture.cpp @@ -29,18 +29,18 @@ namespace android { -/*static*/ const FastCaptureState FastCapture::initial; +/*static*/ const FastCaptureState FastCapture::sInitial; FastCapture::FastCapture() : FastThread(), - inputSource(NULL), inputSourceGen(0), pipeSink(NULL), pipeSinkGen(0), - readBuffer(NULL), readBufferState(-1), format(Format_Invalid), sampleRate(0), - // dummyDumpState - totalNativeFramesRead(0) + mInputSource(NULL), mInputSourceGen(0), mPipeSink(NULL), mPipeSinkGen(0), + mReadBuffer(NULL), mReadBufferState(-1), mFormat(Format_Invalid), mSampleRate(0), + // mDummyDumpState + mTotalNativeFramesRead(0) { - previous = &initial; - current = &initial; + mPrevious = &sInitial; + mCurrent = &sInitial; - mDummyDumpState = &dummyDumpState; + mDummyDumpState = &mDummyFastCaptureDumpState; } FastCapture::~FastCapture() @@ -63,13 +63,13 @@ void FastCapture::setLog(NBLog::Writer *logWriter __unused) void FastCapture::onIdle() { - preIdle = *(const FastCaptureState *)current; - current = &preIdle; + mPreIdle = *(const FastCaptureState *)mCurrent; + mCurrent = &mPreIdle; } void FastCapture::onExit() { - delete[] readBuffer; + free(mReadBuffer); } bool FastCapture::isSubClassCommand(FastThreadState::Command command) @@ -86,67 +86,67 @@ bool FastCapture::isSubClassCommand(FastThreadState::Command command) void FastCapture::onStateChange() { - const FastCaptureState * const current = (const FastCaptureState *) this->current; - const FastCaptureState * const previous = (const FastCaptureState *) this->previous; - FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) this->dumpState; + const FastCaptureState * const current = (const FastCaptureState *) mCurrent; + const FastCaptureState * const previous = (const FastCaptureState *) mPrevious; + FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) mDumpState; const size_t frameCount = current->mFrameCount; bool eitherChanged = false; // check for change in input HAL configuration - NBAIO_Format previousFormat = format; - if (current->mInputSourceGen != inputSourceGen) { - inputSource = current->mInputSource; - inputSourceGen = current->mInputSourceGen; - if (inputSource == NULL) { - format = Format_Invalid; - sampleRate = 0; + NBAIO_Format previousFormat = mFormat; + if (current->mInputSourceGen != mInputSourceGen) { + mInputSource = current->mInputSource; + mInputSourceGen = current->mInputSourceGen; + if (mInputSource == NULL) { + mFormat = Format_Invalid; + mSampleRate = 0; } else { - format = inputSource->format(); - sampleRate = Format_sampleRate(format); - unsigned channelCount = Format_channelCount(format); + mFormat = mInputSource->format(); + mSampleRate = Format_sampleRate(mFormat); + unsigned channelCount = Format_channelCount(mFormat); ALOG_ASSERT(channelCount == 1 || channelCount == 2); } - dumpState->mSampleRate = sampleRate; + dumpState->mSampleRate = mSampleRate; eitherChanged = true; } // check for change in pipe - if (current->mPipeSinkGen != pipeSinkGen) { - pipeSink = current->mPipeSink; - pipeSinkGen = current->mPipeSinkGen; + if (current->mPipeSinkGen != mPipeSinkGen) { + mPipeSink = current->mPipeSink; + mPipeSinkGen = current->mPipeSinkGen; eitherChanged = true; } // input source and pipe sink must be compatible - if (eitherChanged && inputSource != NULL && pipeSink != NULL) { - ALOG_ASSERT(Format_isEqual(format, pipeSink->format())); + if (eitherChanged && mInputSource != NULL && mPipeSink != NULL) { + ALOG_ASSERT(Format_isEqual(mFormat, mPipeSink->format())); } - if ((!Format_isEqual(format, previousFormat)) || (frameCount != previous->mFrameCount)) { - // FIXME to avoid priority inversion, don't delete here - delete[] readBuffer; - readBuffer = NULL; - if (frameCount > 0 && sampleRate > 0) { + if ((!Format_isEqual(mFormat, previousFormat)) || (frameCount != previous->mFrameCount)) { + // FIXME to avoid priority inversion, don't free here + free(mReadBuffer); + mReadBuffer = NULL; + if (frameCount > 0 && mSampleRate > 0) { // FIXME new may block for unbounded time at internal mutex of the heap // implementation; it would be better to have normal capture thread allocate for // us to avoid blocking here and to prevent possible priority inversion - unsigned channelCount = Format_channelCount(format); - // FIXME frameSize - readBuffer = new short[frameCount * channelCount]; - periodNs = (frameCount * 1000000000LL) / sampleRate; // 1.00 - underrunNs = (frameCount * 1750000000LL) / sampleRate; // 1.75 - overrunNs = (frameCount * 500000000LL) / sampleRate; // 0.50 - forceNs = (frameCount * 950000000LL) / sampleRate; // 0.95 - warmupNs = (frameCount * 500000000LL) / sampleRate; // 0.50 + (void)posix_memalign(&mReadBuffer, 32, frameCount * Format_frameSize(mFormat)); + mPeriodNs = (frameCount * 1000000000LL) / mSampleRate; // 1.00 + mUnderrunNs = (frameCount * 1750000000LL) / mSampleRate; // 1.75 + mOverrunNs = (frameCount * 500000000LL) / mSampleRate; // 0.50 + mForceNs = (frameCount * 950000000LL) / mSampleRate; // 0.95 + mWarmupNsMin = (frameCount * 750000000LL) / mSampleRate; // 0.75 + mWarmupNsMax = (frameCount * 1250000000LL) / mSampleRate; // 1.25 } else { - periodNs = 0; - underrunNs = 0; - overrunNs = 0; - forceNs = 0; - warmupNs = 0; + mPeriodNs = 0; + mUnderrunNs = 0; + mOverrunNs = 0; + mForceNs = 0; + mWarmupNsMin = 0; + mWarmupNsMax = LONG_MAX; } - readBufferState = -1; + mReadBufferState = -1; dumpState->mFrameCount = frameCount; } @@ -154,44 +154,43 @@ void FastCapture::onStateChange() void FastCapture::onWork() { - const FastCaptureState * const current = (const FastCaptureState *) this->current; - FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) this->dumpState; - const FastCaptureState::Command command = this->command; + const FastCaptureState * const current = (const FastCaptureState *) mCurrent; + FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) mDumpState; + const FastCaptureState::Command command = mCommand; const size_t frameCount = current->mFrameCount; if ((command & FastCaptureState::READ) /*&& isWarm*/) { - ALOG_ASSERT(inputSource != NULL); - ALOG_ASSERT(readBuffer != NULL); + ALOG_ASSERT(mInputSource != NULL); + ALOG_ASSERT(mReadBuffer != NULL); dumpState->mReadSequence++; ATRACE_BEGIN("read"); - ssize_t framesRead = inputSource->read(readBuffer, frameCount, + ssize_t framesRead = mInputSource->read(mReadBuffer, frameCount, AudioBufferProvider::kInvalidPTS); ATRACE_END(); dumpState->mReadSequence++; if (framesRead >= 0) { LOG_ALWAYS_FATAL_IF((size_t) framesRead > frameCount); - totalNativeFramesRead += framesRead; - dumpState->mFramesRead = totalNativeFramesRead; - readBufferState = framesRead; + mTotalNativeFramesRead += framesRead; + dumpState->mFramesRead = mTotalNativeFramesRead; + mReadBufferState = framesRead; } else { dumpState->mReadErrors++; - readBufferState = 0; + mReadBufferState = 0; } // FIXME rename to attemptedIO - attemptedWrite = true; + mAttemptedWrite = true; } if (command & FastCaptureState::WRITE) { - ALOG_ASSERT(pipeSink != NULL); - ALOG_ASSERT(readBuffer != NULL); - if (readBufferState < 0) { - unsigned channelCount = Format_channelCount(format); - // FIXME frameSize - memset(readBuffer, 0, frameCount * channelCount * sizeof(short)); - readBufferState = frameCount; + ALOG_ASSERT(mPipeSink != NULL); + ALOG_ASSERT(mReadBuffer != NULL); + if (mReadBufferState < 0) { + unsigned channelCount = Format_channelCount(mFormat); + memset(mReadBuffer, 0, frameCount * Format_frameSize(mFormat)); + mReadBufferState = frameCount; } - if (readBufferState > 0) { - ssize_t framesWritten = pipeSink->write(readBuffer, readBufferState); + if (mReadBufferState > 0) { + ssize_t framesWritten = mPipeSink->write(mReadBuffer, mReadBufferState); // FIXME This supports at most one fast capture client. // To handle multiple clients this could be converted to an array, // or with a lot more work the control block could be shared by all clients. @@ -210,13 +209,4 @@ void FastCapture::onWork() } } -FastCaptureDumpState::FastCaptureDumpState() : FastThreadDumpState(), - mReadSequence(0), mFramesRead(0), mReadErrors(0), mSampleRate(0), mFrameCount(0) -{ -} - -FastCaptureDumpState::~FastCaptureDumpState() -{ -} - } // namespace android diff --git a/services/audioflinger/FastCapture.h b/services/audioflinger/FastCapture.h index e535b9d..e258a4d 100644 --- a/services/audioflinger/FastCapture.h +++ b/services/audioflinger/FastCapture.h @@ -20,23 +20,12 @@ #include "FastThread.h" #include "StateQueue.h" #include "FastCaptureState.h" +#include "FastCaptureDumpState.h" namespace android { typedef StateQueue<FastCaptureState> FastCaptureStateQueue; -struct FastCaptureDumpState : FastThreadDumpState { - FastCaptureDumpState(); - /*virtual*/ ~FastCaptureDumpState(); - - // FIXME by renaming, could pull up many of these to FastThreadDumpState - uint32_t mReadSequence; // incremented before and after each read() - uint32_t mFramesRead; // total number of frames read successfully - uint32_t mReadErrors; // total number of read() errors - uint32_t mSampleRate; - size_t mFrameCount; -}; - class FastCapture : public FastThread { public: @@ -57,19 +46,21 @@ private: virtual void onStateChange(); virtual void onWork(); - static const FastCaptureState initial; - FastCaptureState preIdle; // copy of state before we went into idle + static const FastCaptureState sInitial; + + FastCaptureState mPreIdle; // copy of state before we went into idle // FIXME by renaming, could pull up many of these to FastThread - NBAIO_Source *inputSource; - int inputSourceGen; - NBAIO_Sink *pipeSink; - int pipeSinkGen; - short *readBuffer; - ssize_t readBufferState; // number of initialized frames in readBuffer, or -1 to clear - NBAIO_Format format; - unsigned sampleRate; - FastCaptureDumpState dummyDumpState; - uint32_t totalNativeFramesRead; // copied to dumpState->mFramesRead + NBAIO_Source* mInputSource; + int mInputSourceGen; + NBAIO_Sink* mPipeSink; + int mPipeSinkGen; + void* mReadBuffer; + ssize_t mReadBufferState; // number of initialized frames in readBuffer, + // or -1 to clear + NBAIO_Format mFormat; + unsigned mSampleRate; + FastCaptureDumpState mDummyFastCaptureDumpState; + uint32_t mTotalNativeFramesRead; // copied to dumpState->mFramesRead }; // class FastCapture diff --git a/services/audioflinger/FastCaptureDumpState.cpp b/services/audioflinger/FastCaptureDumpState.cpp new file mode 100644 index 0000000..53eeba5 --- /dev/null +++ b/services/audioflinger/FastCaptureDumpState.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "FastCaptureDumpState" +//define LOG_NDEBUG 0 + +#include "Configuration.h" +#include <utils/Log.h> +#include "FastCaptureDumpState.h" +#include "FastCaptureState.h" + +namespace android { + +FastCaptureDumpState::FastCaptureDumpState() : FastThreadDumpState(), + mReadSequence(0), mFramesRead(0), mReadErrors(0), mSampleRate(0), mFrameCount(0) +{ +} + +FastCaptureDumpState::~FastCaptureDumpState() +{ +} + +void FastCaptureDumpState::dump(int fd) const +{ + if (mCommand == FastCaptureState::INITIAL) { + dprintf(fd, " FastCapture not initialized\n"); + return; + } + double measuredWarmupMs = (mMeasuredWarmupTs.tv_sec * 1000.0) + + (mMeasuredWarmupTs.tv_nsec / 1000000.0); + double periodSec = (double) mFrameCount / mSampleRate; + dprintf(fd, " FastCapture command=%s readSequence=%u framesRead=%u\n" + " readErrors=%u sampleRate=%u frameCount=%zu\n" + " measuredWarmup=%.3g ms, warmupCycles=%u period=%.2f ms\n", + FastCaptureState::commandToString(mCommand), mReadSequence, mFramesRead, + mReadErrors, mSampleRate, mFrameCount, measuredWarmupMs, mWarmupCycles, + periodSec * 1e3); +} + +} // android diff --git a/services/audioflinger/FastCaptureDumpState.h b/services/audioflinger/FastCaptureDumpState.h new file mode 100644 index 0000000..6f9c4c3 --- /dev/null +++ b/services/audioflinger/FastCaptureDumpState.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_AUDIO_FAST_CAPTURE_DUMP_STATE_H +#define ANDROID_AUDIO_FAST_CAPTURE_DUMP_STATE_H + +#include <stdint.h> +#include "Configuration.h" +#include "FastThreadDumpState.h" + +namespace android { + +struct FastCaptureDumpState : FastThreadDumpState { + FastCaptureDumpState(); + /*virtual*/ ~FastCaptureDumpState(); + + void dump(int fd) const; // should only be called on a stable copy, not the original + + // FIXME by renaming, could pull up many of these to FastThreadDumpState + uint32_t mReadSequence; // incremented before and after each read() + uint32_t mFramesRead; // total number of frames read successfully + uint32_t mReadErrors; // total number of read() errors + uint32_t mSampleRate; + size_t mFrameCount; +}; + +} // android + +#endif // ANDROID_AUDIO_FAST_CAPTURE_DUMP_STATE_H diff --git a/services/audioflinger/FastCaptureState.cpp b/services/audioflinger/FastCaptureState.cpp index 1d029b7..c4d5e45 100644 --- a/services/audioflinger/FastCaptureState.cpp +++ b/services/audioflinger/FastCaptureState.cpp @@ -27,4 +27,19 @@ FastCaptureState::~FastCaptureState() { } +// static +const char *FastCaptureState::commandToString(Command command) +{ + const char *str = FastThreadState::commandToString(command); + if (str != NULL) { + return str; + } + switch (command) { + case FastCaptureState::READ: return "READ"; + case FastCaptureState::WRITE: return "WRITE"; + case FastCaptureState::READ_WRITE: return "READ_WRITE"; + } + LOG_ALWAYS_FATAL("%s", __func__); +} + } // android diff --git a/services/audioflinger/FastCaptureState.h b/services/audioflinger/FastCaptureState.h index 29c865a..9bca2d4 100644 --- a/services/audioflinger/FastCaptureState.h +++ b/services/audioflinger/FastCaptureState.h @@ -29,21 +29,23 @@ struct FastCaptureState : FastThreadState { /*virtual*/ ~FastCaptureState(); // all pointer fields use raw pointers; objects are owned and ref-counted by RecordThread - NBAIO_Source *mInputSource; // HAL input device, must already be negotiated + NBAIO_Source* mInputSource; // HAL input device, must already be negotiated // FIXME by renaming, could pull up these fields to FastThreadState int mInputSourceGen; // increment when mInputSource is assigned - NBAIO_Sink *mPipeSink; // after reading from input source, write to this pipe sink + NBAIO_Sink* mPipeSink; // after reading from input source, write to this pipe sink int mPipeSinkGen; // increment when mPipeSink is assigned size_t mFrameCount; // number of frames per fast capture buffer - audio_track_cblk_t *mCblk; // control block for the single fast client, or NULL + audio_track_cblk_t* mCblk; // control block for the single fast client, or NULL // Extends FastThreadState::Command static const Command // The following commands also process configuration changes, and can be "or"ed: - READ = 0x8, // read from input source - WRITE = 0x10, // write to pipe sink - READ_WRITE = 0x18; // read from input source and write to pipe sink + READ = 0x8, // read from input source + WRITE = 0x10, // write to pipe sink + READ_WRITE = 0x18; // read from input source and write to pipe sink + // never returns NULL; asserts if command is invalid + static const char *commandToString(Command command); }; // struct FastCaptureState } // namespace android diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp index 2678cbf..f1cf0aa 100644 --- a/services/audioflinger/FastMixer.cpp +++ b/services/audioflinger/FastMixer.cpp @@ -27,10 +27,11 @@ #include "Configuration.h" #include <time.h> +#include <utils/Debug.h> #include <utils/Log.h> #include <utils/Trace.h> #include <system/audio.h> -#ifdef FAST_MIXER_STATISTICS +#ifdef FAST_THREAD_STATISTICS #include <cpustats/CentralTendencyStatistics.h> #ifdef CPU_FREQUENCY_STATISTICS #include <cpustats/ThreadCpuUsage.h> @@ -44,15 +45,15 @@ namespace android { -/*static*/ const FastMixerState FastMixer::initial; +/*static*/ const FastMixerState FastMixer::sInitial; FastMixer::FastMixer() : FastThread(), - slopNs(0), - // fastTrackNames - // generations - outputSink(NULL), - outputSinkGen(0), - mixer(NULL), + mSlopNs(0), + // mFastTrackNames + // mGenerations + mOutputSink(NULL), + mOutputSinkGen(0), + mMixer(NULL), mSinkBuffer(NULL), mSinkBufferSize(0), mSinkChannelCount(FCC_2), @@ -60,30 +61,30 @@ FastMixer::FastMixer() : FastThread(), mMixerBufferSize(0), mMixerBufferFormat(AUDIO_FORMAT_PCM_16_BIT), mMixerBufferState(UNDEFINED), - format(Format_Invalid), - sampleRate(0), - fastTracksGen(0), - totalNativeFramesWritten(0), + mFormat(Format_Invalid), + mSampleRate(0), + mFastTracksGen(0), + mTotalNativeFramesWritten(0), // timestamp - nativeFramesWrittenButNotPresented(0) // the = 0 is to silence the compiler + mNativeFramesWrittenButNotPresented(0) // the = 0 is to silence the compiler { - // FIXME pass initial as parameter to base class constructor, and make it static local - previous = &initial; - current = &initial; + // FIXME pass sInitial as parameter to base class constructor, and make it static local + mPrevious = &sInitial; + mCurrent = &sInitial; - mDummyDumpState = &dummyDumpState; + mDummyDumpState = &mDummyFastMixerDumpState; // TODO: Add channel mask to NBAIO_Format. // We assume that the channel mask must be a valid positional channel mask. mSinkChannelMask = audio_channel_out_mask_from_count(mSinkChannelCount); unsigned i; for (i = 0; i < FastMixerState::kMaxFastTracks; ++i) { - fastTrackNames[i] = -1; - generations[i] = 0; + mFastTrackNames[i] = -1; + mGenerations[i] = 0; } -#ifdef FAST_MIXER_STATISTICS - oldLoad.tv_sec = 0; - oldLoad.tv_nsec = 0; +#ifdef FAST_THREAD_STATISTICS + mOldLoad.tv_sec = 0; + mOldLoad.tv_nsec = 0; #endif } @@ -103,20 +104,20 @@ const FastThreadState *FastMixer::poll() void FastMixer::setLog(NBLog::Writer *logWriter) { - if (mixer != NULL) { - mixer->setLog(logWriter); + if (mMixer != NULL) { + mMixer->setLog(logWriter); } } void FastMixer::onIdle() { - preIdle = *(const FastMixerState *)current; - current = &preIdle; + mPreIdle = *(const FastMixerState *)mCurrent; + mCurrent = &mPreIdle; } void FastMixer::onExit() { - delete mixer; + delete mMixer; free(mMixerBuffer); free(mSinkBuffer); } @@ -135,82 +136,84 @@ bool FastMixer::isSubClassCommand(FastThreadState::Command command) void FastMixer::onStateChange() { - const FastMixerState * const current = (const FastMixerState *) this->current; - const FastMixerState * const previous = (const FastMixerState *) this->previous; - FastMixerDumpState * const dumpState = (FastMixerDumpState *) this->dumpState; + const FastMixerState * const current = (const FastMixerState *) mCurrent; + const FastMixerState * const previous = (const FastMixerState *) mPrevious; + FastMixerDumpState * const dumpState = (FastMixerDumpState *) mDumpState; const size_t frameCount = current->mFrameCount; // handle state change here, but since we want to diff the state, - // we're prepared for previous == &initial the first time through + // we're prepared for previous == &sInitial the first time through unsigned previousTrackMask; // check for change in output HAL configuration - NBAIO_Format previousFormat = format; - if (current->mOutputSinkGen != outputSinkGen) { - outputSink = current->mOutputSink; - outputSinkGen = current->mOutputSinkGen; - if (outputSink == NULL) { - format = Format_Invalid; - sampleRate = 0; + NBAIO_Format previousFormat = mFormat; + if (current->mOutputSinkGen != mOutputSinkGen) { + mOutputSink = current->mOutputSink; + mOutputSinkGen = current->mOutputSinkGen; + if (mOutputSink == NULL) { + mFormat = Format_Invalid; + mSampleRate = 0; mSinkChannelCount = 0; mSinkChannelMask = AUDIO_CHANNEL_NONE; } else { - format = outputSink->format(); - sampleRate = Format_sampleRate(format); - mSinkChannelCount = Format_channelCount(format); + mFormat = mOutputSink->format(); + mSampleRate = Format_sampleRate(mFormat); + mSinkChannelCount = Format_channelCount(mFormat); LOG_ALWAYS_FATAL_IF(mSinkChannelCount > AudioMixer::MAX_NUM_CHANNELS); // TODO: Add channel mask to NBAIO_Format // We assume that the channel mask must be a valid positional channel mask. mSinkChannelMask = audio_channel_out_mask_from_count(mSinkChannelCount); } - dumpState->mSampleRate = sampleRate; + dumpState->mSampleRate = mSampleRate; } - if ((!Format_isEqual(format, previousFormat)) || (frameCount != previous->mFrameCount)) { + if ((!Format_isEqual(mFormat, previousFormat)) || (frameCount != previous->mFrameCount)) { // FIXME to avoid priority inversion, don't delete here - delete mixer; - mixer = NULL; + delete mMixer; + mMixer = NULL; free(mMixerBuffer); mMixerBuffer = NULL; free(mSinkBuffer); mSinkBuffer = NULL; - if (frameCount > 0 && sampleRate > 0) { + if (frameCount > 0 && mSampleRate > 0) { // 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 - mixer = new AudioMixer(frameCount, sampleRate, FastMixerState::kMaxFastTracks); + mMixer = new AudioMixer(frameCount, mSampleRate, FastMixerState::kMaxFastTracks); const size_t mixerFrameSize = mSinkChannelCount * audio_bytes_per_sample(mMixerBufferFormat); mMixerBufferSize = mixerFrameSize * frameCount; (void)posix_memalign(&mMixerBuffer, 32, mMixerBufferSize); const size_t sinkFrameSize = mSinkChannelCount - * audio_bytes_per_sample(format.mFormat); + * audio_bytes_per_sample(mFormat.mFormat); if (sinkFrameSize > mixerFrameSize) { // need a sink buffer mSinkBufferSize = sinkFrameSize * frameCount; (void)posix_memalign(&mSinkBuffer, 32, mSinkBufferSize); } - periodNs = (frameCount * 1000000000LL) / sampleRate; // 1.00 - underrunNs = (frameCount * 1750000000LL) / sampleRate; // 1.75 - overrunNs = (frameCount * 500000000LL) / sampleRate; // 0.50 - forceNs = (frameCount * 950000000LL) / sampleRate; // 0.95 - warmupNs = (frameCount * 500000000LL) / sampleRate; // 0.50 + mPeriodNs = (frameCount * 1000000000LL) / mSampleRate; // 1.00 + mUnderrunNs = (frameCount * 1750000000LL) / mSampleRate; // 1.75 + mOverrunNs = (frameCount * 500000000LL) / mSampleRate; // 0.50 + mForceNs = (frameCount * 950000000LL) / mSampleRate; // 0.95 + mWarmupNsMin = (frameCount * 750000000LL) / mSampleRate; // 0.75 + mWarmupNsMax = (frameCount * 1250000000LL) / mSampleRate; // 1.25 } else { - periodNs = 0; - underrunNs = 0; - overrunNs = 0; - forceNs = 0; - warmupNs = 0; + mPeriodNs = 0; + mUnderrunNs = 0; + mOverrunNs = 0; + mForceNs = 0; + mWarmupNsMin = 0; + mWarmupNsMax = LONG_MAX; } mMixerBufferState = UNDEFINED; #if !LOG_NDEBUG for (unsigned i = 0; i < FastMixerState::kMaxFastTracks; ++i) { - fastTrackNames[i] = -1; + mFastTrackNames[i] = -1; } #endif // we need to reconfigure all active tracks previousTrackMask = 0; - fastTracksGen = current->mFastTracksGen - 1; + mFastTracksGen = current->mFastTracksGen - 1; dumpState->mFrameCount = frameCount; } else { previousTrackMask = previous->mTrackMask; @@ -219,7 +222,7 @@ void FastMixer::onStateChange() // check for change in active track set const unsigned currentTrackMask = current->mTrackMask; dumpState->mTrackMask = currentTrackMask; - if (current->mFastTracksGen != fastTracksGen) { + if (current->mFastTracksGen != mFastTracksGen) { ALOG_ASSERT(mMixerBuffer != NULL); int name; @@ -230,16 +233,16 @@ void FastMixer::onStateChange() removedTracks &= ~(1 << i); const FastTrack* fastTrack = ¤t->mFastTracks[i]; ALOG_ASSERT(fastTrack->mBufferProvider == NULL); - if (mixer != NULL) { - name = fastTrackNames[i]; + if (mMixer != NULL) { + name = mFastTrackNames[i]; ALOG_ASSERT(name >= 0); - mixer->deleteTrackName(name); + mMixer->deleteTrackName(name); } #if !LOG_NDEBUG - fastTrackNames[i] = -1; + mFastTrackNames[i] = -1; #endif // don't reset track dump state, since other side is ignoring it - generations[i] = fastTrack->mGeneration; + mGenerations[i] = fastTrack->mGeneration; } // now process added tracks @@ -249,29 +252,29 @@ void FastMixer::onStateChange() addedTracks &= ~(1 << i); const FastTrack* fastTrack = ¤t->mFastTracks[i]; AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider; - ALOG_ASSERT(bufferProvider != NULL && fastTrackNames[i] == -1); - if (mixer != NULL) { - name = mixer->getTrackName(fastTrack->mChannelMask, + ALOG_ASSERT(bufferProvider != NULL && mFastTrackNames[i] == -1); + if (mMixer != NULL) { + name = mMixer->getTrackName(fastTrack->mChannelMask, fastTrack->mFormat, AUDIO_SESSION_OUTPUT_MIX); ALOG_ASSERT(name >= 0); - fastTrackNames[i] = name; - mixer->setBufferProvider(name, bufferProvider); - mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER, + mFastTrackNames[i] = name; + mMixer->setBufferProvider(name, bufferProvider); + mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER, (void *)mMixerBuffer); // newly allocated track names default to full scale volume - mixer->setParameter( + mMixer->setParameter( name, AudioMixer::TRACK, AudioMixer::MIXER_FORMAT, (void *)mMixerBufferFormat); - mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT, + mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT, (void *)(uintptr_t)fastTrack->mFormat); - mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK, + mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK, (void *)(uintptr_t)fastTrack->mChannelMask); - mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK, + mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK, (void *)(uintptr_t)mSinkChannelMask); - mixer->enable(name); + mMixer->enable(name); } - generations[i] = fastTrack->mGeneration; + mGenerations[i] = fastTrack->mGeneration; } // finally process (potentially) modified tracks; these use the same slot @@ -281,38 +284,38 @@ void FastMixer::onStateChange() int i = __builtin_ctz(modifiedTracks); modifiedTracks &= ~(1 << i); const FastTrack* fastTrack = ¤t->mFastTracks[i]; - if (fastTrack->mGeneration != generations[i]) { + if (fastTrack->mGeneration != mGenerations[i]) { // this track was actually modified AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider; ALOG_ASSERT(bufferProvider != NULL); - if (mixer != NULL) { - name = fastTrackNames[i]; + if (mMixer != NULL) { + name = mFastTrackNames[i]; ALOG_ASSERT(name >= 0); - mixer->setBufferProvider(name, bufferProvider); + mMixer->setBufferProvider(name, bufferProvider); if (fastTrack->mVolumeProvider == NULL) { float f = AudioMixer::UNITY_GAIN_FLOAT; - mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &f); - mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &f); + mMixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &f); + mMixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &f); } - mixer->setParameter(name, AudioMixer::RESAMPLE, + mMixer->setParameter(name, AudioMixer::RESAMPLE, AudioMixer::REMOVE, NULL); - mixer->setParameter( + mMixer->setParameter( name, AudioMixer::TRACK, AudioMixer::MIXER_FORMAT, (void *)mMixerBufferFormat); - mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT, + mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT, (void *)(uintptr_t)fastTrack->mFormat); - mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK, + mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK, (void *)(uintptr_t)fastTrack->mChannelMask); - mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK, + mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK, (void *)(uintptr_t)mSinkChannelMask); // already enabled } - generations[i] = fastTrack->mGeneration; + mGenerations[i] = fastTrack->mGeneration; } } - fastTracksGen = current->mFastTracksGen; + mFastTracksGen = current->mFastTracksGen; dumpState->mNumTracks = popcount(currentTrackMask); } @@ -320,12 +323,12 @@ void FastMixer::onStateChange() void FastMixer::onWork() { - const FastMixerState * const current = (const FastMixerState *) this->current; - FastMixerDumpState * const dumpState = (FastMixerDumpState *) this->dumpState; - const FastMixerState::Command command = this->command; + const FastMixerState * const current = (const FastMixerState *) mCurrent; + FastMixerDumpState * const dumpState = (FastMixerDumpState *) mDumpState; + const FastMixerState::Command command = mCommand; const size_t frameCount = current->mFrameCount; - if ((command & FastMixerState::MIX) && (mixer != NULL) && isWarm) { + if ((command & FastMixerState::MIX) && (mMixer != NULL) && mIsWarm) { ALOG_ASSERT(mMixerBuffer != NULL); // for each track, update volume and check for underrun unsigned currentTrackMask = current->mTrackMask; @@ -335,9 +338,9 @@ void FastMixer::onWork() const FastTrack* fastTrack = ¤t->mFastTracks[i]; // Refresh the per-track timestamp - if (timestampStatus == NO_ERROR) { + if (mTimestampStatus == NO_ERROR) { uint32_t trackFramesWrittenButNotPresented = - nativeFramesWrittenButNotPresented; + mNativeFramesWrittenButNotPresented; uint32_t trackFramesWritten = fastTrack->mBufferProvider->framesReleased(); // Can't provide an AudioTimestamp before first frame presented, // or during the brief 32-bit wraparound window @@ -345,20 +348,20 @@ void FastMixer::onWork() AudioTimestamp perTrackTimestamp; perTrackTimestamp.mPosition = trackFramesWritten - trackFramesWrittenButNotPresented; - perTrackTimestamp.mTime = timestamp.mTime; + perTrackTimestamp.mTime = mTimestamp.mTime; fastTrack->mBufferProvider->onTimestamp(perTrackTimestamp); } } - int name = fastTrackNames[i]; + int name = mFastTrackNames[i]; ALOG_ASSERT(name >= 0); if (fastTrack->mVolumeProvider != NULL) { gain_minifloat_packed_t vlr = fastTrack->mVolumeProvider->getVolumeLR(); float vlf = float_from_gain(gain_minifloat_unpack_left(vlr)); float vrf = float_from_gain(gain_minifloat_unpack_right(vlr)); - mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &vlf); - mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &vrf); + mMixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &vlf); + mMixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &vrf); } // FIXME The current implementation of framesReady() for fast tracks // takes a tryLock, which can block @@ -379,43 +382,44 @@ void FastMixer::onWork() if (framesReady == 0) { underruns.mBitFields.mEmpty++; underruns.mBitFields.mMostRecent = UNDERRUN_EMPTY; - mixer->disable(name); + mMixer->disable(name); } else { // allow mixing partial buffer underruns.mBitFields.mPartial++; underruns.mBitFields.mMostRecent = UNDERRUN_PARTIAL; - mixer->enable(name); + mMixer->enable(name); } } else { underruns.mBitFields.mFull++; underruns.mBitFields.mMostRecent = UNDERRUN_FULL; - mixer->enable(name); + mMixer->enable(name); } ftDump->mUnderruns = underruns; ftDump->mFramesReady = framesReady; } int64_t pts; - if (outputSink == NULL || (OK != outputSink->getNextWriteTimestamp(&pts))) { + if (mOutputSink == NULL || (OK != mOutputSink->getNextWriteTimestamp(&pts))) { pts = AudioBufferProvider::kInvalidPTS; } // process() is CPU-bound - mixer->process(pts); + mMixer->process(pts); mMixerBufferState = MIXED; } else if (mMixerBufferState == MIXED) { mMixerBufferState = UNDEFINED; } //bool didFullWrite = false; // dumpsys could display a count of partial writes - if ((command & FastMixerState::WRITE) && (outputSink != NULL) && (mMixerBuffer != NULL)) { + if ((command & FastMixerState::WRITE) && (mOutputSink != NULL) && (mMixerBuffer != NULL)) { if (mMixerBufferState == UNDEFINED) { memset(mMixerBuffer, 0, mMixerBufferSize); mMixerBufferState = ZEROED; } + // prepare the buffer used to write to sink void *buffer = mSinkBuffer != NULL ? mSinkBuffer : mMixerBuffer; - if (format.mFormat != mMixerBufferFormat) { // sink format not the same as mixer format - memcpy_by_audio_format(buffer, format.mFormat, mMixerBuffer, mMixerBufferFormat, - frameCount * Format_channelCount(format)); + if (mFormat.mFormat != mMixerBufferFormat) { // sink format not the same as mixer format + memcpy_by_audio_format(buffer, mFormat.mFormat, mMixerBuffer, mMixerBufferFormat, + frameCount * Format_channelCount(mFormat)); } // if non-NULL, then duplicate write() to this non-blocking sink NBAIO_Sink* teeSink; @@ -426,252 +430,34 @@ void FastMixer::onWork() // but this code should be modified to handle both non-blocking and blocking sinks dumpState->mWriteSequence++; ATRACE_BEGIN("write"); - ssize_t framesWritten = outputSink->write(buffer, frameCount); + ssize_t framesWritten = mOutputSink->write(buffer, frameCount); ATRACE_END(); dumpState->mWriteSequence++; if (framesWritten >= 0) { ALOG_ASSERT((size_t) framesWritten <= frameCount); - totalNativeFramesWritten += framesWritten; - dumpState->mFramesWritten = totalNativeFramesWritten; + mTotalNativeFramesWritten += framesWritten; + dumpState->mFramesWritten = mTotalNativeFramesWritten; //if ((size_t) framesWritten == frameCount) { // didFullWrite = true; //} } else { dumpState->mWriteErrors++; } - attemptedWrite = true; + mAttemptedWrite = true; // FIXME count # of writes blocked excessively, CPU usage, etc. for dump - timestampStatus = outputSink->getTimestamp(timestamp); - if (timestampStatus == NO_ERROR) { - uint32_t totalNativeFramesPresented = timestamp.mPosition; - if (totalNativeFramesPresented <= totalNativeFramesWritten) { - nativeFramesWrittenButNotPresented = - totalNativeFramesWritten - totalNativeFramesPresented; + mTimestampStatus = mOutputSink->getTimestamp(mTimestamp); + if (mTimestampStatus == NO_ERROR) { + uint32_t totalNativeFramesPresented = mTimestamp.mPosition; + if (totalNativeFramesPresented <= mTotalNativeFramesWritten) { + mNativeFramesWrittenButNotPresented = + mTotalNativeFramesWritten - totalNativeFramesPresented; } else { // HAL reported that more frames were presented than were written - timestampStatus = INVALID_OPERATION; + mTimestampStatus = INVALID_OPERATION; } } } } -FastMixerDumpState::FastMixerDumpState( -#ifdef FAST_MIXER_STATISTICS - uint32_t samplingN -#endif - ) : FastThreadDumpState(), - mWriteSequence(0), mFramesWritten(0), - mNumTracks(0), mWriteErrors(0), - mSampleRate(0), mFrameCount(0), - mTrackMask(0) -{ -#ifdef FAST_MIXER_STATISTICS - increaseSamplingN(samplingN); -#endif -} - -#ifdef FAST_MIXER_STATISTICS -void FastMixerDumpState::increaseSamplingN(uint32_t samplingN) -{ - if (samplingN <= mSamplingN || samplingN > kSamplingN || roundup(samplingN) != samplingN) { - return; - } - uint32_t additional = samplingN - mSamplingN; - // sample arrays aren't accessed atomically with respect to the bounds, - // so clearing reduces chance for dumpsys to read random uninitialized samples - memset(&mMonotonicNs[mSamplingN], 0, sizeof(mMonotonicNs[0]) * additional); - memset(&mLoadNs[mSamplingN], 0, sizeof(mLoadNs[0]) * additional); -#ifdef CPU_FREQUENCY_STATISTICS - memset(&mCpukHz[mSamplingN], 0, sizeof(mCpukHz[0]) * additional); -#endif - mSamplingN = samplingN; -} -#endif - -FastMixerDumpState::~FastMixerDumpState() -{ -} - -// helper function called by qsort() -static int compare_uint32_t(const void *pa, const void *pb) -{ - uint32_t a = *(const uint32_t *)pa; - uint32_t b = *(const uint32_t *)pb; - if (a < b) { - return -1; - } else if (a > b) { - return 1; - } else { - return 0; - } -} - -void FastMixerDumpState::dump(int fd) const -{ - if (mCommand == FastMixerState::INITIAL) { - dprintf(fd, " FastMixer not initialized\n"); - return; - } -#define COMMAND_MAX 32 - char string[COMMAND_MAX]; - switch (mCommand) { - case FastMixerState::INITIAL: - strcpy(string, "INITIAL"); - break; - case FastMixerState::HOT_IDLE: - strcpy(string, "HOT_IDLE"); - break; - case FastMixerState::COLD_IDLE: - strcpy(string, "COLD_IDLE"); - break; - case FastMixerState::EXIT: - strcpy(string, "EXIT"); - break; - case FastMixerState::MIX: - strcpy(string, "MIX"); - break; - case FastMixerState::WRITE: - strcpy(string, "WRITE"); - break; - case FastMixerState::MIX_WRITE: - strcpy(string, "MIX_WRITE"); - break; - default: - snprintf(string, COMMAND_MAX, "%d", mCommand); - break; - } - double measuredWarmupMs = (mMeasuredWarmupTs.tv_sec * 1000.0) + - (mMeasuredWarmupTs.tv_nsec / 1000000.0); - double mixPeriodSec = (double) mFrameCount / (double) mSampleRate; - dprintf(fd, " FastMixer command=%s writeSequence=%u framesWritten=%u\n" - " numTracks=%u writeErrors=%u underruns=%u overruns=%u\n" - " sampleRate=%u frameCount=%zu measuredWarmup=%.3g ms, warmupCycles=%u\n" - " mixPeriod=%.2f ms\n", - string, mWriteSequence, mFramesWritten, - mNumTracks, mWriteErrors, mUnderruns, mOverruns, - mSampleRate, mFrameCount, measuredWarmupMs, mWarmupCycles, - mixPeriodSec * 1e3); -#ifdef FAST_MIXER_STATISTICS - // find the interval of valid samples - uint32_t bounds = mBounds; - uint32_t newestOpen = bounds & 0xFFFF; - uint32_t oldestClosed = bounds >> 16; - uint32_t n = (newestOpen - oldestClosed) & 0xFFFF; - if (n > mSamplingN) { - ALOGE("too many samples %u", n); - n = mSamplingN; - } - // statistics for monotonic (wall clock) time, thread raw CPU load in time, CPU clock frequency, - // and adjusted CPU load in MHz normalized for CPU clock frequency - CentralTendencyStatistics wall, loadNs; -#ifdef CPU_FREQUENCY_STATISTICS - CentralTendencyStatistics kHz, loadMHz; - uint32_t previousCpukHz = 0; -#endif - // Assuming a normal distribution for cycle times, three standard deviations on either side of - // the mean account for 99.73% of the population. So if we take each tail to be 1/1000 of the - // sample set, we get 99.8% combined, or close to three standard deviations. - static const uint32_t kTailDenominator = 1000; - uint32_t *tail = n >= kTailDenominator ? new uint32_t[n] : NULL; - // loop over all the samples - for (uint32_t j = 0; j < n; ++j) { - size_t i = oldestClosed++ & (mSamplingN - 1); - uint32_t wallNs = mMonotonicNs[i]; - if (tail != NULL) { - tail[j] = wallNs; - } - wall.sample(wallNs); - uint32_t sampleLoadNs = mLoadNs[i]; - loadNs.sample(sampleLoadNs); -#ifdef CPU_FREQUENCY_STATISTICS - uint32_t sampleCpukHz = mCpukHz[i]; - // skip bad kHz samples - if ((sampleCpukHz & ~0xF) != 0) { - kHz.sample(sampleCpukHz >> 4); - if (sampleCpukHz == previousCpukHz) { - double megacycles = (double) sampleLoadNs * (double) (sampleCpukHz >> 4) * 1e-12; - double adjMHz = megacycles / mixPeriodSec; // _not_ wallNs * 1e9 - loadMHz.sample(adjMHz); - } - } - previousCpukHz = sampleCpukHz; -#endif - } - if (n) { - dprintf(fd, " Simple moving statistics over last %.1f seconds:\n", - wall.n() * mixPeriodSec); - dprintf(fd, " wall clock time in ms per mix cycle:\n" - " mean=%.2f min=%.2f max=%.2f stddev=%.2f\n", - wall.mean()*1e-6, wall.minimum()*1e-6, wall.maximum()*1e-6, - wall.stddev()*1e-6); - dprintf(fd, " raw CPU load in us per mix cycle:\n" - " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n", - loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3, - loadNs.stddev()*1e-3); - } else { - dprintf(fd, " No FastMixer statistics available currently\n"); - } -#ifdef CPU_FREQUENCY_STATISTICS - dprintf(fd, " CPU clock frequency in MHz:\n" - " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n", - kHz.mean()*1e-3, kHz.minimum()*1e-3, kHz.maximum()*1e-3, kHz.stddev()*1e-3); - dprintf(fd, " adjusted CPU load in MHz (i.e. normalized for CPU clock frequency):\n" - " mean=%.1f min=%.1f max=%.1f stddev=%.1f\n", - loadMHz.mean(), loadMHz.minimum(), loadMHz.maximum(), loadMHz.stddev()); -#endif - if (tail != NULL) { - qsort(tail, n, sizeof(uint32_t), compare_uint32_t); - // assume same number of tail samples on each side, left and right - uint32_t count = n / kTailDenominator; - CentralTendencyStatistics left, right; - for (uint32_t i = 0; i < count; ++i) { - left.sample(tail[i]); - right.sample(tail[n - (i + 1)]); - } - dprintf(fd, " Distribution of mix cycle times in ms for the tails (> ~3 stddev outliers):\n" - " left tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n" - " right tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n", - left.mean()*1e-6, left.minimum()*1e-6, left.maximum()*1e-6, left.stddev()*1e-6, - right.mean()*1e-6, right.minimum()*1e-6, right.maximum()*1e-6, - right.stddev()*1e-6); - delete[] tail; - } -#endif - // The active track mask and track states are updated non-atomically. - // So if we relied on isActive to decide whether to display, - // then we might display an obsolete track or omit an active track. - // Instead we always display all tracks, with an indication - // of whether we think the track is active. - uint32_t trackMask = mTrackMask; - dprintf(fd, " Fast tracks: kMaxFastTracks=%u activeMask=%#x\n", - FastMixerState::kMaxFastTracks, trackMask); - dprintf(fd, " Index Active Full Partial Empty Recent Ready\n"); - for (uint32_t i = 0; i < FastMixerState::kMaxFastTracks; ++i, trackMask >>= 1) { - bool isActive = trackMask & 1; - const FastTrackDump *ftDump = &mTracks[i]; - const FastTrackUnderruns& underruns = ftDump->mUnderruns; - const char *mostRecent; - switch (underruns.mBitFields.mMostRecent) { - case UNDERRUN_FULL: - mostRecent = "full"; - break; - case UNDERRUN_PARTIAL: - mostRecent = "partial"; - break; - case UNDERRUN_EMPTY: - mostRecent = "empty"; - break; - default: - mostRecent = "?"; - break; - } - dprintf(fd, " %5u %6s %4u %7u %5u %7s %5zu\n", i, isActive ? "yes" : "no", - (underruns.mBitFields.mFull) & UNDERRUN_MASK, - (underruns.mBitFields.mPartial) & UNDERRUN_MASK, - (underruns.mBitFields.mEmpty) & UNDERRUN_MASK, - mostRecent, ftDump->mFramesReady); - } -} - } // namespace android diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h index fde8c2b..06a68fb 100644 --- a/services/audioflinger/FastMixer.h +++ b/services/audioflinger/FastMixer.h @@ -17,11 +17,7 @@ #ifndef ANDROID_AUDIO_FAST_MIXER_H #define ANDROID_AUDIO_FAST_MIXER_H -#include <linux/futex.h> -#include <sys/syscall.h> -#include <utils/Debug.h> #include "FastThread.h" -#include <utils/Thread.h> #include "StateQueue.h" #include "FastMixerState.h" #include "FastMixerDumpState.h" @@ -52,36 +48,39 @@ private: virtual void onStateChange(); virtual void onWork(); - // FIXME these former local variables need comments and to be renamed to have "m" prefix - static const FastMixerState initial; - FastMixerState preIdle; // copy of state before we went into idle - long slopNs; // accumulated time we've woken up too early (> 0) or too late (< 0) - int fastTrackNames[FastMixerState::kMaxFastTracks]; // handles used by mixer to identify tracks - int generations[FastMixerState::kMaxFastTracks]; // last observed mFastTracks[i].mGeneration - NBAIO_Sink *outputSink; - int outputSinkGen; - AudioMixer* mixer; + // FIXME these former local variables need comments + static const FastMixerState sInitial; + + FastMixerState mPreIdle; // copy of state before we went into idle + long mSlopNs; // accumulated time we've woken up too early (> 0) or too late (< 0) + int mFastTrackNames[FastMixerState::kMaxFastTracks]; + // handles used by mixer to identify tracks + int mGenerations[FastMixerState::kMaxFastTracks]; + // last observed mFastTracks[i].mGeneration + NBAIO_Sink* mOutputSink; + int mOutputSinkGen; + AudioMixer* mMixer; // mSinkBuffer audio format is stored in format.mFormat. - void* mSinkBuffer; // used for mixer output format translation + void* mSinkBuffer; // used for mixer output format translation // if sink format is different than mixer output. - size_t mSinkBufferSize; - uint32_t mSinkChannelCount; + size_t mSinkBufferSize; + uint32_t mSinkChannelCount; 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). + void* mMixerBuffer; // mixer output buffer. + size_t mMixerBufferSize; + audio_format_t mMixerBufferFormat; // mixer output format: AUDIO_FORMAT_PCM_(16_BIT|FLOAT). enum {UNDEFINED, MIXED, ZEROED} mMixerBufferState; - NBAIO_Format format; - unsigned sampleRate; - int fastTracksGen; - FastMixerDumpState dummyDumpState; - uint32_t totalNativeFramesWritten; // copied to dumpState->mFramesWritten + NBAIO_Format mFormat; + unsigned mSampleRate; + int mFastTracksGen; + FastMixerDumpState mDummyFastMixerDumpState; + uint32_t mTotalNativeFramesWritten; // copied to dumpState->mFramesWritten // next 2 fields are valid only when timestampStatus == NO_ERROR - AudioTimestamp timestamp; - uint32_t nativeFramesWrittenButNotPresented; + AudioTimestamp mTimestamp; + uint32_t mNativeFramesWrittenButNotPresented; }; // class FastMixer diff --git a/services/audioflinger/FastMixerDumpState.cpp b/services/audioflinger/FastMixerDumpState.cpp new file mode 100644 index 0000000..b10942b --- /dev/null +++ b/services/audioflinger/FastMixerDumpState.cpp @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "FastMixerDumpState" +//#define LOG_NDEBUG 0 + +#include "Configuration.h" +#ifdef FAST_THREAD_STATISTICS +#include <cpustats/CentralTendencyStatistics.h> +#ifdef CPU_FREQUENCY_STATISTICS +#include <cpustats/ThreadCpuUsage.h> +#endif +#endif +#include <utils/Debug.h> +#include <utils/Log.h> +#include "FastMixerDumpState.h" + +namespace android { + +FastMixerDumpState::FastMixerDumpState() : FastThreadDumpState(), + mWriteSequence(0), mFramesWritten(0), + mNumTracks(0), mWriteErrors(0), + mSampleRate(0), mFrameCount(0), + mTrackMask(0) +{ +} + +FastMixerDumpState::~FastMixerDumpState() +{ +} + +// helper function called by qsort() +static int compare_uint32_t(const void *pa, const void *pb) +{ + uint32_t a = *(const uint32_t *)pa; + uint32_t b = *(const uint32_t *)pb; + if (a < b) { + return -1; + } else if (a > b) { + return 1; + } else { + return 0; + } +} + +void FastMixerDumpState::dump(int fd) const +{ + if (mCommand == FastMixerState::INITIAL) { + dprintf(fd, " FastMixer not initialized\n"); + return; + } + double measuredWarmupMs = (mMeasuredWarmupTs.tv_sec * 1000.0) + + (mMeasuredWarmupTs.tv_nsec / 1000000.0); + double mixPeriodSec = (double) mFrameCount / mSampleRate; + dprintf(fd, " FastMixer command=%s writeSequence=%u framesWritten=%u\n" + " numTracks=%u writeErrors=%u underruns=%u overruns=%u\n" + " sampleRate=%u frameCount=%zu measuredWarmup=%.3g ms, warmupCycles=%u\n" + " mixPeriod=%.2f ms\n", + FastMixerState::commandToString(mCommand), mWriteSequence, mFramesWritten, + mNumTracks, mWriteErrors, mUnderruns, mOverruns, + mSampleRate, mFrameCount, measuredWarmupMs, mWarmupCycles, + mixPeriodSec * 1e3); +#ifdef FAST_THREAD_STATISTICS + // find the interval of valid samples + uint32_t bounds = mBounds; + uint32_t newestOpen = bounds & 0xFFFF; + uint32_t oldestClosed = bounds >> 16; + uint32_t n = (newestOpen - oldestClosed) & 0xFFFF; + if (n > mSamplingN) { + ALOGE("too many samples %u", n); + n = mSamplingN; + } + // statistics for monotonic (wall clock) time, thread raw CPU load in time, CPU clock frequency, + // and adjusted CPU load in MHz normalized for CPU clock frequency + CentralTendencyStatistics wall, loadNs; +#ifdef CPU_FREQUENCY_STATISTICS + CentralTendencyStatistics kHz, loadMHz; + uint32_t previousCpukHz = 0; +#endif + // Assuming a normal distribution for cycle times, three standard deviations on either side of + // the mean account for 99.73% of the population. So if we take each tail to be 1/1000 of the + // sample set, we get 99.8% combined, or close to three standard deviations. + static const uint32_t kTailDenominator = 1000; + uint32_t *tail = n >= kTailDenominator ? new uint32_t[n] : NULL; + // loop over all the samples + for (uint32_t j = 0; j < n; ++j) { + size_t i = oldestClosed++ & (mSamplingN - 1); + uint32_t wallNs = mMonotonicNs[i]; + if (tail != NULL) { + tail[j] = wallNs; + } + wall.sample(wallNs); + uint32_t sampleLoadNs = mLoadNs[i]; + loadNs.sample(sampleLoadNs); +#ifdef CPU_FREQUENCY_STATISTICS + uint32_t sampleCpukHz = mCpukHz[i]; + // skip bad kHz samples + if ((sampleCpukHz & ~0xF) != 0) { + kHz.sample(sampleCpukHz >> 4); + if (sampleCpukHz == previousCpukHz) { + double megacycles = (double) sampleLoadNs * (double) (sampleCpukHz >> 4) * 1e-12; + double adjMHz = megacycles / mixPeriodSec; // _not_ wallNs * 1e9 + loadMHz.sample(adjMHz); + } + } + previousCpukHz = sampleCpukHz; +#endif + } + if (n) { + dprintf(fd, " Simple moving statistics over last %.1f seconds:\n", + wall.n() * mixPeriodSec); + dprintf(fd, " wall clock time in ms per mix cycle:\n" + " mean=%.2f min=%.2f max=%.2f stddev=%.2f\n", + wall.mean()*1e-6, wall.minimum()*1e-6, wall.maximum()*1e-6, + wall.stddev()*1e-6); + dprintf(fd, " raw CPU load in us per mix cycle:\n" + " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n", + loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3, + loadNs.stddev()*1e-3); + } else { + dprintf(fd, " No FastMixer statistics available currently\n"); + } +#ifdef CPU_FREQUENCY_STATISTICS + dprintf(fd, " CPU clock frequency in MHz:\n" + " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n", + kHz.mean()*1e-3, kHz.minimum()*1e-3, kHz.maximum()*1e-3, kHz.stddev()*1e-3); + dprintf(fd, " adjusted CPU load in MHz (i.e. normalized for CPU clock frequency):\n" + " mean=%.1f min=%.1f max=%.1f stddev=%.1f\n", + loadMHz.mean(), loadMHz.minimum(), loadMHz.maximum(), loadMHz.stddev()); +#endif + if (tail != NULL) { + qsort(tail, n, sizeof(uint32_t), compare_uint32_t); + // assume same number of tail samples on each side, left and right + uint32_t count = n / kTailDenominator; + CentralTendencyStatistics left, right; + for (uint32_t i = 0; i < count; ++i) { + left.sample(tail[i]); + right.sample(tail[n - (i + 1)]); + } + dprintf(fd, " Distribution of mix cycle times in ms for the tails " + "(> ~3 stddev outliers):\n" + " left tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n" + " right tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n", + left.mean()*1e-6, left.minimum()*1e-6, left.maximum()*1e-6, left.stddev()*1e-6, + right.mean()*1e-6, right.minimum()*1e-6, right.maximum()*1e-6, + right.stddev()*1e-6); + delete[] tail; + } +#endif + // The active track mask and track states are updated non-atomically. + // So if we relied on isActive to decide whether to display, + // then we might display an obsolete track or omit an active track. + // Instead we always display all tracks, with an indication + // of whether we think the track is active. + uint32_t trackMask = mTrackMask; + dprintf(fd, " Fast tracks: kMaxFastTracks=%u activeMask=%#x\n", + FastMixerState::kMaxFastTracks, trackMask); + dprintf(fd, " Index Active Full Partial Empty Recent Ready\n"); + for (uint32_t i = 0; i < FastMixerState::kMaxFastTracks; ++i, trackMask >>= 1) { + bool isActive = trackMask & 1; + const FastTrackDump *ftDump = &mTracks[i]; + const FastTrackUnderruns& underruns = ftDump->mUnderruns; + const char *mostRecent; + switch (underruns.mBitFields.mMostRecent) { + case UNDERRUN_FULL: + mostRecent = "full"; + break; + case UNDERRUN_PARTIAL: + mostRecent = "partial"; + break; + case UNDERRUN_EMPTY: + mostRecent = "empty"; + break; + default: + mostRecent = "?"; + break; + } + dprintf(fd, " %5u %6s %4u %7u %5u %7s %5zu\n", i, isActive ? "yes" : "no", + (underruns.mBitFields.mFull) & UNDERRUN_MASK, + (underruns.mBitFields.mPartial) & UNDERRUN_MASK, + (underruns.mBitFields.mEmpty) & UNDERRUN_MASK, + mostRecent, ftDump->mFramesReady); + } +} + +} // android diff --git a/services/audioflinger/FastMixerDumpState.h b/services/audioflinger/FastMixerDumpState.h index 6a1e464..ac15e7c 100644 --- a/services/audioflinger/FastMixerDumpState.h +++ b/services/audioflinger/FastMixerDumpState.h @@ -17,7 +17,10 @@ #ifndef ANDROID_AUDIO_FAST_MIXER_DUMP_STATE_H #define ANDROID_AUDIO_FAST_MIXER_DUMP_STATE_H +#include <stdint.h> #include "Configuration.h" +#include "FastThreadDumpState.h" +#include "FastMixerState.h" namespace android { @@ -52,22 +55,12 @@ private: struct FastTrackDump { FastTrackDump() : mFramesReady(0) { } /*virtual*/ ~FastTrackDump() { } - FastTrackUnderruns mUnderruns; - size_t mFramesReady; // most recent value only; no long-term statistics kept + FastTrackUnderruns mUnderruns; + size_t mFramesReady; // most recent value only; no long-term statistics kept }; -// The FastMixerDumpState keeps a cache of FastMixer statistics that can be logged by dumpsys. -// Each individual native word-sized field is accessed atomically. But the -// overall structure is non-atomic, that is there may be an inconsistency between fields. -// No barriers or locks are used for either writing or reading. -// Only POD types are permitted, and the contents shouldn't be trusted (i.e. do range checks). -// It has a different lifetime than the FastMixer, and so it can't be a member of FastMixer. struct FastMixerDumpState : FastThreadDumpState { - FastMixerDumpState( -#ifdef FAST_MIXER_STATISTICS - uint32_t samplingN = kSamplingNforLowRamDevice -#endif - ); + FastMixerDumpState(); /*virtual*/ ~FastMixerDumpState(); void dump(int fd) const; // should only be called on a stable copy, not the original @@ -80,14 +73,6 @@ struct FastMixerDumpState : FastThreadDumpState { size_t mFrameCount; uint32_t mTrackMask; // mask of active tracks FastTrackDump mTracks[FastMixerState::kMaxFastTracks]; - -#ifdef FAST_MIXER_STATISTICS - // Compile-time constant for a "low RAM device", must be a power of 2 <= kSamplingN. - // This value was chosen such that each array uses 1 small page (4 Kbytes). - static const uint32_t kSamplingNforLowRamDevice = 0x400; - // Increase sampling window after construction, must be a power of 2 <= kSamplingN - void increaseSamplingN(uint32_t samplingN); -#endif }; } // android diff --git a/services/audioflinger/FastMixerState.cpp b/services/audioflinger/FastMixerState.cpp index 3aa8dad..a8c2634 100644 --- a/services/audioflinger/FastMixerState.cpp +++ b/services/audioflinger/FastMixerState.cpp @@ -39,4 +39,19 @@ FastMixerState::~FastMixerState() { } +// static +const char *FastMixerState::commandToString(Command command) +{ + const char *str = FastThreadState::commandToString(command); + if (str != NULL) { + return str; + } + switch (command) { + case FastMixerState::MIX: return "MIX"; + case FastMixerState::WRITE: return "WRITE"; + case FastMixerState::MIX_WRITE: return "MIX_WRITE"; + } + LOG_ALWAYS_FATAL("%s", __func__); +} + } // namespace android diff --git a/services/audioflinger/FastMixerState.h b/services/audioflinger/FastMixerState.h index 661c9ca..916514f 100644 --- a/services/audioflinger/FastMixerState.h +++ b/services/audioflinger/FastMixerState.h @@ -73,6 +73,9 @@ struct FastMixerState : FastThreadState { // This might be a one-time configuration rather than per-state NBAIO_Sink* mTeeSink; // if non-NULL, then duplicate write()s to this non-blocking sink + + // never returns NULL; asserts if command is invalid + static const char *commandToString(Command command); }; // struct FastMixerState } // namespace android diff --git a/services/audioflinger/FastThread.cpp b/services/audioflinger/FastThread.cpp index 216dace..5ca579b 100644 --- a/services/audioflinger/FastThread.cpp +++ b/services/audioflinger/FastThread.cpp @@ -25,54 +25,58 @@ #include <utils/Log.h> #include <utils/Trace.h> #include "FastThread.h" +#include "FastThreadDumpState.h" #define FAST_DEFAULT_NS 999999999L // ~1 sec: default time to sleep #define FAST_HOT_IDLE_NS 1000000L // 1 ms: time to sleep while hot idling -#define MIN_WARMUP_CYCLES 2 // minimum number of loop cycles to wait for warmup +#define MIN_WARMUP_CYCLES 2 // minimum number of consecutive in-range loop cycles + // to wait for warmup #define MAX_WARMUP_CYCLES 10 // maximum number of loop cycles to wait for warmup namespace android { FastThread::FastThread() : Thread(false /*canCallJava*/), - // re-initialized to &initial by subclass constructor - previous(NULL), current(NULL), - /* oldTs({0, 0}), */ - oldTsValid(false), - sleepNs(-1), - periodNs(0), - underrunNs(0), - overrunNs(0), - forceNs(0), - warmupNs(0), - // re-initialized to &dummyDumpState by subclass constructor + // re-initialized to &sInitial by subclass constructor + mPrevious(NULL), mCurrent(NULL), + /* mOldTs({0, 0}), */ + mOldTsValid(false), + mSleepNs(-1), + mPeriodNs(0), + mUnderrunNs(0), + mOverrunNs(0), + mForceNs(0), + mWarmupNsMin(0), + mWarmupNsMax(LONG_MAX), + // re-initialized to &mDummySubclassDumpState by subclass constructor mDummyDumpState(NULL), - dumpState(NULL), - ignoreNextOverrun(true), -#ifdef FAST_MIXER_STATISTICS - // oldLoad - oldLoadValid(false), - bounds(0), - full(false), - // tcu + mDumpState(NULL), + mIgnoreNextOverrun(true), +#ifdef FAST_THREAD_STATISTICS + // mOldLoad + mOldLoadValid(false), + mBounds(0), + mFull(false), + // mTcu #endif - coldGen(0), - isWarm(false), - /* measuredWarmupTs({0, 0}), */ - warmupCycles(0), - // dummyLogWriter - logWriter(&dummyLogWriter), - timestampStatus(INVALID_OPERATION), + mColdGen(0), + mIsWarm(false), + /* mMeasuredWarmupTs({0, 0}), */ + mWarmupCycles(0), + mWarmupConsecutiveInRangeCycles(0), + // mDummyLogWriter + mLogWriter(&mDummyLogWriter), + mTimestampStatus(INVALID_OPERATION), - command(FastThreadState::INITIAL), + mCommand(FastThreadState::INITIAL), #if 0 frameCount(0), #endif - attemptedWrite(false) + mAttemptedWrite(false) { - oldTs.tv_sec = 0; - oldTs.tv_nsec = 0; - measuredWarmupTs.tv_sec = 0; - measuredWarmupTs.tv_nsec = 0; + mOldTs.tv_sec = 0; + mOldTs.tv_nsec = 0; + mMeasuredWarmupTs.tv_sec = 0; + mMeasuredWarmupTs.tv_nsec = 0; } FastThread::~FastThread() @@ -84,34 +88,34 @@ bool FastThread::threadLoop() for (;;) { // either nanosleep, sched_yield, or busy wait - if (sleepNs >= 0) { - if (sleepNs > 0) { - ALOG_ASSERT(sleepNs < 1000000000); - const struct timespec req = {0, sleepNs}; + if (mSleepNs >= 0) { + if (mSleepNs > 0) { + ALOG_ASSERT(mSleepNs < 1000000000); + const struct timespec req = {0, mSleepNs}; nanosleep(&req, NULL); } else { sched_yield(); } } // default to long sleep for next cycle - sleepNs = FAST_DEFAULT_NS; + mSleepNs = FAST_DEFAULT_NS; // poll for state change const FastThreadState *next = poll(); if (next == NULL) { // continue to use the default initial state until a real state is available - // FIXME &initial not available, should save address earlier - //ALOG_ASSERT(current == &initial && previous == &initial); - next = current; + // FIXME &sInitial not available, should save address earlier + //ALOG_ASSERT(mCurrent == &sInitial && previous == &sInitial); + next = mCurrent; } - command = next->mCommand; - if (next != current) { + mCommand = next->mCommand; + if (next != mCurrent) { // As soon as possible of learning of a new dump area, start using it - dumpState = next->mDumpState != NULL ? next->mDumpState : mDummyDumpState; - logWriter = next->mNBLogWriter != NULL ? next->mNBLogWriter : &dummyLogWriter; - setLog(logWriter); + mDumpState = next->mDumpState != NULL ? next->mDumpState : mDummyDumpState; + mLogWriter = next->mNBLogWriter != NULL ? next->mNBLogWriter : &mDummyLogWriter; + setLog(mLogWriter); // We want to always have a valid reference to the previous (non-idle) state. // However, the state queue only guarantees access to current and previous states. @@ -122,37 +126,38 @@ bool FastThread::threadLoop() // non-idle -> idle update previous from copy of current // idle -> idle don't update previous // idle -> non-idle don't update previous - if (!(current->mCommand & FastThreadState::IDLE)) { - if (command & FastThreadState::IDLE) { + if (!(mCurrent->mCommand & FastThreadState::IDLE)) { + if (mCommand & FastThreadState::IDLE) { onIdle(); - oldTsValid = false; -#ifdef FAST_MIXER_STATISTICS - oldLoadValid = false; + mOldTsValid = false; +#ifdef FAST_THREAD_STATISTICS + mOldLoadValid = false; #endif - ignoreNextOverrun = true; + mIgnoreNextOverrun = true; } - previous = current; + mPrevious = mCurrent; } - current = next; + mCurrent = next; } #if !LOG_NDEBUG next = NULL; // not referenced again #endif - dumpState->mCommand = command; + mDumpState->mCommand = mCommand; + // FIXME what does this comment mean? // << current, previous, command, dumpState >> - switch (command) { + switch (mCommand) { case FastThreadState::INITIAL: case FastThreadState::HOT_IDLE: - sleepNs = FAST_HOT_IDLE_NS; + mSleepNs = FAST_HOT_IDLE_NS; continue; case FastThreadState::COLD_IDLE: // only perform a cold idle command once // FIXME consider checking previous state and only perform if previous != COLD_IDLE - if (current->mColdGen != coldGen) { - int32_t *coldFutexAddr = current->mColdFutexAddr; + if (mCurrent->mColdGen != mColdGen) { + int32_t *coldFutexAddr = mCurrent->mColdFutexAddr; ALOG_ASSERT(coldFutexAddr != NULL); int32_t old = android_atomic_dec(coldFutexAddr); if (old <= 0) { @@ -164,41 +169,42 @@ bool FastThread::threadLoop() } // This may be overly conservative; there could be times that the normal mixer // requests such a brief cold idle that it doesn't require resetting this flag. - isWarm = false; - measuredWarmupTs.tv_sec = 0; - measuredWarmupTs.tv_nsec = 0; - warmupCycles = 0; - sleepNs = -1; - coldGen = current->mColdGen; -#ifdef FAST_MIXER_STATISTICS - bounds = 0; - full = false; + mIsWarm = false; + mMeasuredWarmupTs.tv_sec = 0; + mMeasuredWarmupTs.tv_nsec = 0; + mWarmupCycles = 0; + mWarmupConsecutiveInRangeCycles = 0; + mSleepNs = -1; + mColdGen = mCurrent->mColdGen; +#ifdef FAST_THREAD_STATISTICS + mBounds = 0; + mFull = false; #endif - oldTsValid = !clock_gettime(CLOCK_MONOTONIC, &oldTs); - timestampStatus = INVALID_OPERATION; + mOldTsValid = !clock_gettime(CLOCK_MONOTONIC, &mOldTs); + mTimestampStatus = INVALID_OPERATION; } else { - sleepNs = FAST_HOT_IDLE_NS; + mSleepNs = FAST_HOT_IDLE_NS; } continue; case FastThreadState::EXIT: onExit(); return false; default: - LOG_ALWAYS_FATAL_IF(!isSubClassCommand(command)); + LOG_ALWAYS_FATAL_IF(!isSubClassCommand(mCommand)); break; } // there is a non-idle state available to us; did the state change? - if (current != previous) { + if (mCurrent != mPrevious) { onStateChange(); #if 1 // FIXME shouldn't need this // only process state change once - previous = current; + mPrevious = mCurrent; #endif } // do work using current state here - attemptedWrite = false; + mAttemptedWrite = false; onWork(); // To be exactly periodic, compute the next sleep time based on current time. @@ -207,13 +213,13 @@ bool FastThread::threadLoop() struct timespec newTs; int rc = clock_gettime(CLOCK_MONOTONIC, &newTs); if (rc == 0) { - //logWriter->logTimestamp(newTs); - if (oldTsValid) { - time_t sec = newTs.tv_sec - oldTs.tv_sec; - long nsec = newTs.tv_nsec - oldTs.tv_nsec; + //mLogWriter->logTimestamp(newTs); + if (mOldTsValid) { + time_t sec = newTs.tv_sec - mOldTs.tv_sec; + long nsec = newTs.tv_nsec - mOldTs.tv_nsec; ALOGE_IF(sec < 0 || (sec == 0 && nsec < 0), "clock_gettime(CLOCK_MONOTONIC) failed: was %ld.%09ld but now %ld.%09ld", - oldTs.tv_sec, oldTs.tv_nsec, newTs.tv_sec, newTs.tv_nsec); + mOldTs.tv_sec, mOldTs.tv_nsec, newTs.tv_sec, newTs.tv_nsec); if (nsec < 0) { --sec; nsec += 1000000000; @@ -221,62 +227,70 @@ bool FastThread::threadLoop() // To avoid an initial underrun on fast tracks after exiting standby, // do not start pulling data from tracks and mixing until warmup is complete. // Warmup is considered complete after the earlier of: - // MIN_WARMUP_CYCLES write() attempts and last one blocks for at least warmupNs + // MIN_WARMUP_CYCLES consecutive in-range write() attempts, + // where "in-range" means mWarmupNsMin <= cycle time <= mWarmupNsMax // MAX_WARMUP_CYCLES write() attempts. // This is overly conservative, but to get better accuracy requires a new HAL API. - if (!isWarm && attemptedWrite) { - measuredWarmupTs.tv_sec += sec; - measuredWarmupTs.tv_nsec += nsec; - if (measuredWarmupTs.tv_nsec >= 1000000000) { - measuredWarmupTs.tv_sec++; - measuredWarmupTs.tv_nsec -= 1000000000; + if (!mIsWarm && mAttemptedWrite) { + mMeasuredWarmupTs.tv_sec += sec; + mMeasuredWarmupTs.tv_nsec += nsec; + if (mMeasuredWarmupTs.tv_nsec >= 1000000000) { + mMeasuredWarmupTs.tv_sec++; + mMeasuredWarmupTs.tv_nsec -= 1000000000; } - ++warmupCycles; - if ((nsec > warmupNs && warmupCycles >= MIN_WARMUP_CYCLES) || - (warmupCycles >= MAX_WARMUP_CYCLES)) { - isWarm = true; - dumpState->mMeasuredWarmupTs = measuredWarmupTs; - dumpState->mWarmupCycles = warmupCycles; + ++mWarmupCycles; + if (mWarmupNsMin <= nsec && nsec <= mWarmupNsMax) { + ALOGV("warmup cycle %d in range: %.03f ms", mWarmupCycles, nsec * 1e-9); + ++mWarmupConsecutiveInRangeCycles; + } else { + ALOGV("warmup cycle %d out of range: %.03f ms", mWarmupCycles, nsec * 1e-9); + mWarmupConsecutiveInRangeCycles = 0; + } + if ((mWarmupConsecutiveInRangeCycles >= MIN_WARMUP_CYCLES) || + (mWarmupCycles >= MAX_WARMUP_CYCLES)) { + mIsWarm = true; + mDumpState->mMeasuredWarmupTs = mMeasuredWarmupTs; + mDumpState->mWarmupCycles = mWarmupCycles; } } - sleepNs = -1; - if (isWarm) { - if (sec > 0 || nsec > underrunNs) { + mSleepNs = -1; + if (mIsWarm) { + if (sec > 0 || nsec > mUnderrunNs) { ATRACE_NAME("underrun"); // FIXME only log occasionally ALOGV("underrun: time since last cycle %d.%03ld sec", (int) sec, nsec / 1000000L); - dumpState->mUnderruns++; - ignoreNextOverrun = true; - } else if (nsec < overrunNs) { - if (ignoreNextOverrun) { - ignoreNextOverrun = false; + mDumpState->mUnderruns++; + mIgnoreNextOverrun = true; + } else if (nsec < mOverrunNs) { + if (mIgnoreNextOverrun) { + mIgnoreNextOverrun = false; } else { // FIXME only log occasionally ALOGV("overrun: time since last cycle %d.%03ld sec", (int) sec, nsec / 1000000L); - dumpState->mOverruns++; + mDumpState->mOverruns++; } // This forces a minimum cycle time. It: // - compensates for an audio HAL with jitter due to sample rate conversion // - works with a variable buffer depth audio HAL that never pulls at a - // rate < than overrunNs per buffer. + // rate < than mOverrunNs per buffer. // - recovers from overrun immediately after underrun // It doesn't work with a non-blocking audio HAL. - sleepNs = forceNs - nsec; + mSleepNs = mForceNs - nsec; } else { - ignoreNextOverrun = false; + mIgnoreNextOverrun = false; } } -#ifdef FAST_MIXER_STATISTICS - if (isWarm) { +#ifdef FAST_THREAD_STATISTICS + if (mIsWarm) { // advance the FIFO queue bounds - size_t i = bounds & (dumpState->mSamplingN - 1); - bounds = (bounds & 0xFFFF0000) | ((bounds + 1) & 0xFFFF); - if (full) { - bounds += 0x10000; - } else if (!(bounds & (dumpState->mSamplingN - 1))) { - full = true; + size_t i = mBounds & (mDumpState->mSamplingN - 1); + mBounds = (mBounds & 0xFFFF0000) | ((mBounds + 1) & 0xFFFF); + if (mFull) { + mBounds += 0x10000; + } else if (!(mBounds & (mDumpState->mSamplingN - 1))) { + mFull = true; } // compute the delta value of clock_gettime(CLOCK_MONOTONIC) uint32_t monotonicNs = nsec; @@ -288,9 +302,9 @@ bool FastThread::threadLoop() struct timespec newLoad; rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &newLoad); if (rc == 0) { - if (oldLoadValid) { - sec = newLoad.tv_sec - oldLoad.tv_sec; - nsec = newLoad.tv_nsec - oldLoad.tv_nsec; + if (mOldLoadValid) { + sec = newLoad.tv_sec - mOldLoad.tv_sec; + nsec = newLoad.tv_nsec - mOldLoad.tv_nsec; if (nsec < 0) { --sec; nsec += 1000000000; @@ -301,42 +315,42 @@ bool FastThread::threadLoop() } } else { // first time through the loop - oldLoadValid = true; + mOldLoadValid = true; } - oldLoad = newLoad; + mOldLoad = newLoad; } #ifdef CPU_FREQUENCY_STATISTICS // get the absolute value of CPU clock frequency in kHz int cpuNum = sched_getcpu(); - uint32_t kHz = tcu.getCpukHz(cpuNum); + uint32_t kHz = mTcu.getCpukHz(cpuNum); kHz = (kHz << 4) | (cpuNum & 0xF); #endif // save values in FIFO queues for dumpsys // these stores #1, #2, #3 are not atomic with respect to each other, // or with respect to store #4 below - dumpState->mMonotonicNs[i] = monotonicNs; - dumpState->mLoadNs[i] = loadNs; + mDumpState->mMonotonicNs[i] = monotonicNs; + mDumpState->mLoadNs[i] = loadNs; #ifdef CPU_FREQUENCY_STATISTICS - dumpState->mCpukHz[i] = kHz; + mDumpState->mCpukHz[i] = kHz; #endif // this store #4 is not atomic with respect to stores #1, #2, #3 above, but // the newest open & oldest closed halves are atomic with respect to each other - dumpState->mBounds = bounds; + mDumpState->mBounds = mBounds; ATRACE_INT("cycle_ms", monotonicNs / 1000000); ATRACE_INT("load_us", loadNs / 1000); } #endif } else { // first time through the loop - oldTsValid = true; - sleepNs = periodNs; - ignoreNextOverrun = true; + mOldTsValid = true; + mSleepNs = mPeriodNs; + mIgnoreNextOverrun = true; } - oldTs = newTs; + mOldTs = newTs; } else { // monotonic clock is broken - oldTsValid = false; - sleepNs = periodNs; + mOldTsValid = false; + mSleepNs = mPeriodNs; } } // for (;;) diff --git a/services/audioflinger/FastThread.h b/services/audioflinger/FastThread.h index 1330334..2efb6de 100644 --- a/services/audioflinger/FastThread.h +++ b/services/audioflinger/FastThread.h @@ -48,42 +48,45 @@ protected: virtual void onStateChange() = 0; virtual void onWork() = 0; - // FIXME these former local variables need comments and to be renamed to have an "m" prefix - const FastThreadState *previous; - const FastThreadState *current; - struct timespec oldTs; - bool oldTsValid; - long sleepNs; // -1: busy wait, 0: sched_yield, > 0: nanosleep - long periodNs; // expected period; the time required to render one mix buffer - long underrunNs; // underrun likely when write cycle is greater than this value - long overrunNs; // overrun likely when write cycle is less than this value - long forceNs; // if overrun detected, force the write cycle to take this much time - long warmupNs; // warmup complete when write cycle is greater than to this value - FastThreadDumpState *mDummyDumpState; - FastThreadDumpState *dumpState; - bool ignoreNextOverrun; // used to ignore initial overrun and first after an underrun -#ifdef FAST_MIXER_STATISTICS - struct timespec oldLoad; // previous value of clock_gettime(CLOCK_THREAD_CPUTIME_ID) - bool oldLoadValid; // whether oldLoad is valid - uint32_t bounds; - bool full; // whether we have collected at least mSamplingN samples + // FIXME these former local variables need comments + const FastThreadState* mPrevious; + const FastThreadState* mCurrent; + struct timespec mOldTs; + bool mOldTsValid; + long mSleepNs; // -1: busy wait, 0: sched_yield, > 0: nanosleep + long mPeriodNs; // expected period; the time required to render one mix buffer + long mUnderrunNs; // underrun likely when write cycle is greater than this value + long mOverrunNs; // overrun likely when write cycle is less than this value + long mForceNs; // if overrun detected, + // force the write cycle to take this much time + long mWarmupNsMin; // warmup complete when write cycle is greater than or equal to + // this value + long mWarmupNsMax; // and less than or equal to this value + FastThreadDumpState* mDummyDumpState; + FastThreadDumpState* mDumpState; + bool mIgnoreNextOverrun; // used to ignore initial overrun and first after an + // underrun +#ifdef FAST_THREAD_STATISTICS + struct timespec mOldLoad; // previous value of clock_gettime(CLOCK_THREAD_CPUTIME_ID) + bool mOldLoadValid; // whether oldLoad is valid + uint32_t mBounds; + bool mFull; // whether we have collected at least mSamplingN samples #ifdef CPU_FREQUENCY_STATISTICS - ThreadCpuUsage tcu; // for reading the current CPU clock frequency in kHz + ThreadCpuUsage mTcu; // for reading the current CPU clock frequency in kHz #endif #endif - unsigned coldGen; // last observed mColdGen - bool isWarm; // true means ready to mix, false means wait for warmup before mixing - struct timespec measuredWarmupTs; // how long did it take for warmup to complete - uint32_t warmupCycles; // counter of number of loop cycles required to warmup - NBLog::Writer dummyLogWriter; - NBLog::Writer *logWriter; - status_t timestampStatus; + unsigned mColdGen; // last observed mColdGen + bool mIsWarm; // true means ready to mix, + // false means wait for warmup before mixing + struct timespec mMeasuredWarmupTs; // how long did it take for warmup to complete + uint32_t mWarmupCycles; // counter of number of loop cycles during warmup phase + uint32_t mWarmupConsecutiveInRangeCycles; // number of consecutive cycles in range + NBLog::Writer mDummyLogWriter; + NBLog::Writer* mLogWriter; + status_t mTimestampStatus; - FastThreadState::Command command; -#if 0 - size_t frameCount; -#endif - bool attemptedWrite; + FastThreadState::Command mCommand; + bool mAttemptedWrite; }; // class FastThread diff --git a/services/audioflinger/FastThreadDumpState.cpp b/services/audioflinger/FastThreadDumpState.cpp new file mode 100644 index 0000000..9df5c4c --- /dev/null +++ b/services/audioflinger/FastThreadDumpState.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "FastThreadDumpState.h" + +namespace android { + +FastThreadDumpState::FastThreadDumpState() : + mCommand(FastThreadState::INITIAL), mUnderruns(0), mOverruns(0), + /* mMeasuredWarmupTs({0, 0}), */ + mWarmupCycles(0) +#ifdef FAST_THREAD_STATISTICS + , mSamplingN(0), mBounds(0) +#endif +{ + mMeasuredWarmupTs.tv_sec = 0; + mMeasuredWarmupTs.tv_nsec = 0; +#ifdef FAST_THREAD_STATISTICS + increaseSamplingN(1); +#endif +} + +FastThreadDumpState::~FastThreadDumpState() +{ +} + +#ifdef FAST_THREAD_STATISTICS +void FastThreadDumpState::increaseSamplingN(uint32_t samplingN) +{ + if (samplingN <= mSamplingN || samplingN > kSamplingN || roundup(samplingN) != samplingN) { + return; + } + uint32_t additional = samplingN - mSamplingN; + // sample arrays aren't accessed atomically with respect to the bounds, + // so clearing reduces chance for dumpsys to read random uninitialized samples + memset(&mMonotonicNs[mSamplingN], 0, sizeof(mMonotonicNs[0]) * additional); + memset(&mLoadNs[mSamplingN], 0, sizeof(mLoadNs[0]) * additional); +#ifdef CPU_FREQUENCY_STATISTICS + memset(&mCpukHz[mSamplingN], 0, sizeof(mCpukHz[0]) * additional); +#endif + mSamplingN = samplingN; +} +#endif + +} // android diff --git a/services/audioflinger/FastThreadDumpState.h b/services/audioflinger/FastThreadDumpState.h new file mode 100644 index 0000000..1ce0914 --- /dev/null +++ b/services/audioflinger/FastThreadDumpState.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_AUDIO_FAST_THREAD_DUMP_STATE_H +#define ANDROID_AUDIO_FAST_THREAD_DUMP_STATE_H + +#include "Configuration.h" +#include "FastThreadState.h" + +namespace android { + +// The FastThreadDumpState keeps a cache of FastThread statistics that can be logged by dumpsys. +// Each individual native word-sized field is accessed atomically. But the +// overall structure is non-atomic, that is there may be an inconsistency between fields. +// No barriers or locks are used for either writing or reading. +// Only POD types are permitted, and the contents shouldn't be trusted (i.e. do range checks). +// It has a different lifetime than the FastThread, and so it can't be a member of FastThread. +struct FastThreadDumpState { + FastThreadDumpState(); + /*virtual*/ ~FastThreadDumpState(); + + FastThreadState::Command mCommand; // current command + uint32_t mUnderruns; // total number of underruns + uint32_t mOverruns; // total number of overruns + struct timespec mMeasuredWarmupTs; // measured warmup time + uint32_t mWarmupCycles; // number of loop cycles required to warmup + +#ifdef FAST_THREAD_STATISTICS + // Recently collected samples of per-cycle monotonic time, thread CPU time, and CPU frequency. + // kSamplingN is max size of sampling frame (statistics), and must be a power of 2 <= 0x8000. + // The sample arrays are virtually allocated based on this compile-time constant, + // but are only initialized and used based on the runtime parameter mSamplingN. + static const uint32_t kSamplingN = 0x8000; + // Compile-time constant for a "low RAM device", must be a power of 2 <= kSamplingN. + // This value was chosen such that each array uses 1 small page (4 Kbytes). + static const uint32_t kSamplingNforLowRamDevice = 0x400; + // Corresponding runtime maximum size of sample arrays, must be a power of 2 <= kSamplingN. + uint32_t mSamplingN; + // The bounds define the interval of valid samples, and are represented as follows: + // newest open (excluded) endpoint = lower 16 bits of bounds, modulo N + // oldest closed (included) endpoint = upper 16 bits of bounds, modulo N + // Number of valid samples is newest - oldest. + uint32_t mBounds; // bounds for mMonotonicNs, mThreadCpuNs, and mCpukHz + // The elements in the *Ns arrays are in units of nanoseconds <= 3999999999. + uint32_t mMonotonicNs[kSamplingN]; // delta monotonic (wall clock) time + uint32_t mLoadNs[kSamplingN]; // delta CPU load in time +#ifdef CPU_FREQUENCY_STATISTICS + uint32_t mCpukHz[kSamplingN]; // absolute CPU clock frequency in kHz, bits 0-3 are CPU# +#endif + + // Increase sampling window after construction, must be a power of 2 <= kSamplingN + void increaseSamplingN(uint32_t samplingN); +#endif + +}; // struct FastThreadDumpState + +} // android + +#endif // ANDROID_AUDIO_FAST_THREAD_DUMP_STATE_H diff --git a/services/audioflinger/FastThreadState.cpp b/services/audioflinger/FastThreadState.cpp index 6994872..ad5f31f 100644 --- a/services/audioflinger/FastThreadState.cpp +++ b/services/audioflinger/FastThreadState.cpp @@ -29,21 +29,16 @@ FastThreadState::~FastThreadState() { } - -FastThreadDumpState::FastThreadDumpState() : - mCommand(FastThreadState::INITIAL), mUnderruns(0), mOverruns(0), - /* mMeasuredWarmupTs({0, 0}), */ - mWarmupCycles(0) -#ifdef FAST_MIXER_STATISTICS - , mSamplingN(1), mBounds(0) -#endif -{ - mMeasuredWarmupTs.tv_sec = 0; - mMeasuredWarmupTs.tv_nsec = 0; -} - -FastThreadDumpState::~FastThreadDumpState() +// static +const char *FastThreadState::commandToString(FastThreadState::Command command) { + switch (command) { + case FastThreadState::INITIAL: return "INITIAL"; + case FastThreadState::HOT_IDLE: return "HOT_IDLE"; + case FastThreadState::COLD_IDLE: return "COLD_IDLE"; + case FastThreadState::EXIT: return "EXIT"; + } + return NULL; } } // namespace android diff --git a/services/audioflinger/FastThreadState.h b/services/audioflinger/FastThreadState.h index 1ab8a0a..f18f846 100644 --- a/services/audioflinger/FastThreadState.h +++ b/services/audioflinger/FastThreadState.h @@ -46,43 +46,10 @@ struct FastThreadState { FastThreadDumpState* mDumpState; // if non-NULL, then update dump state periodically NBLog::Writer* mNBLogWriter; // non-blocking logger + // returns NULL if command belongs to a subclass + static const char *commandToString(Command command); }; // struct FastThreadState - -// FIXME extract common part of comment at FastMixerDumpState -struct FastThreadDumpState { - FastThreadDumpState(); - /*virtual*/ ~FastThreadDumpState(); - - FastThreadState::Command mCommand; // current command - uint32_t mUnderruns; // total number of underruns - uint32_t mOverruns; // total number of overruns - struct timespec mMeasuredWarmupTs; // measured warmup time - uint32_t mWarmupCycles; // number of loop cycles required to warmup - -#ifdef FAST_MIXER_STATISTICS - // Recently collected samples of per-cycle monotonic time, thread CPU time, and CPU frequency. - // kSamplingN is max size of sampling frame (statistics), and must be a power of 2 <= 0x8000. - // The sample arrays are virtually allocated based on this compile-time constant, - // but are only initialized and used based on the runtime parameter mSamplingN. - static const uint32_t kSamplingN = 0x8000; - // Corresponding runtime maximum size of sample arrays, must be a power of 2 <= kSamplingN. - uint32_t mSamplingN; - // The bounds define the interval of valid samples, and are represented as follows: - // newest open (excluded) endpoint = lower 16 bits of bounds, modulo N - // oldest closed (included) endpoint = upper 16 bits of bounds, modulo N - // Number of valid samples is newest - oldest. - uint32_t mBounds; // bounds for mMonotonicNs, mThreadCpuNs, and mCpukHz - // The elements in the *Ns arrays are in units of nanoseconds <= 3999999999. - uint32_t mMonotonicNs[kSamplingN]; // delta monotonic (wall clock) time - uint32_t mLoadNs[kSamplingN]; // delta CPU load in time -#ifdef CPU_FREQUENCY_STATISTICS - uint32_t mCpukHz[kSamplingN]; // absolute CPU clock frequency in kHz, bits 0-3 are CPU# -#endif -#endif - -}; // struct FastThreadDumpState - } // android #endif // ANDROID_AUDIO_FAST_THREAD_STATE_H diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp index 7544052..efbdcff 100644 --- a/services/audioflinger/PatchPanel.cpp +++ b/services/audioflinger/PatchPanel.cpp @@ -166,7 +166,9 @@ status_t AudioFlinger::PatchPanel::createAudioPatch(const struct audio_patch *pa if (*handle == mPatches[index]->mHandle) { ALOGV("createAudioPatch() removing patch handle %d", *handle); halHandle = mPatches[index]->mHalHandle; + Patch *removedPatch = mPatches[index]; mPatches.removeAt(index); + delete removedPatch; break; } } @@ -692,4 +694,4 @@ status_t AudioFlinger::PatchPanel::setAudioPortConfig(const struct audio_port_co } -}; // namespace android +} // namespace android diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h index ee48276..902d5e4 100644 --- a/services/audioflinger/PlaybackTracks.h +++ b/services/audioflinger/PlaybackTracks.h @@ -255,7 +255,7 @@ public: class Buffer : public AudioBufferProvider::Buffer { public: - int16_t *mBuffer; + void *mBuffer; }; OutputTrack(PlaybackThread *thread, @@ -271,7 +271,7 @@ public: AudioSystem::SYNC_EVENT_NONE, int triggerSession = 0); virtual void stop(); - bool write(int16_t* data, uint32_t frames); + bool write(void* data, uint32_t frames); bool bufferQueueEmpty() const { return mBufferQueue.size() == 0; } bool isActive() const { return mActive; } const wp<ThreadBase>& thread() const { return mThread; } diff --git a/services/audioflinger/StateQueue.cpp b/services/audioflinger/StateQueue.cpp index 40d7bcd..9d4188f 100644 --- a/services/audioflinger/StateQueue.cpp +++ b/services/audioflinger/StateQueue.cpp @@ -48,7 +48,7 @@ template<typename T> StateQueue<T>::StateQueue() : , mObserverDump(&mObserverDummyDump), mMutatorDump(&mMutatorDummyDump) #endif { - atomic_init(&mNext, 0); + atomic_init(&mNext, static_cast<uintptr_t>(0)); } template<typename T> StateQueue<T>::~StateQueue() diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 6b9da83..9881764 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -23,7 +23,9 @@ #include "Configuration.h" #include <math.h> #include <fcntl.h> +#include <linux/futex.h> #include <sys/stat.h> +#include <sys/syscall.h> #include <cutils/properties.h> #include <media/AudioParameter.h> #include <media/AudioResamplerPublic.h> @@ -314,6 +316,165 @@ void CpuStats::sample(const String8 &title // ThreadBase // ---------------------------------------------------------------------------- +// static +const char *AudioFlinger::ThreadBase::threadTypeToString(AudioFlinger::ThreadBase::type_t type) +{ + switch (type) { + case MIXER: + return "MIXER"; + case DIRECT: + return "DIRECT"; + case DUPLICATING: + return "DUPLICATING"; + case RECORD: + return "RECORD"; + case OFFLOAD: + return "OFFLOAD"; + default: + return "unknown"; + } +} + +String8 devicesToString(audio_devices_t devices) +{ + static const struct mapping { + audio_devices_t mDevices; + const char * mString; + } mappingsOut[] = { + AUDIO_DEVICE_OUT_EARPIECE, "EARPIECE", + AUDIO_DEVICE_OUT_SPEAKER, "SPEAKER", + AUDIO_DEVICE_OUT_WIRED_HEADSET, "WIRED_HEADSET", + AUDIO_DEVICE_OUT_WIRED_HEADPHONE, "WIRED_HEADPHONE", + AUDIO_DEVICE_OUT_TELEPHONY_TX, "TELEPHONY_TX", + AUDIO_DEVICE_NONE, "NONE", // must be last + }, mappingsIn[] = { + AUDIO_DEVICE_IN_BUILTIN_MIC, "BUILTIN_MIC", + AUDIO_DEVICE_IN_WIRED_HEADSET, "WIRED_HEADSET", + AUDIO_DEVICE_IN_VOICE_CALL, "VOICE_CALL", + AUDIO_DEVICE_IN_REMOTE_SUBMIX, "REMOTE_SUBMIX", + AUDIO_DEVICE_NONE, "NONE", // must be last + }; + String8 result; + audio_devices_t allDevices = AUDIO_DEVICE_NONE; + const mapping *entry; + if (devices & AUDIO_DEVICE_BIT_IN) { + devices &= ~AUDIO_DEVICE_BIT_IN; + entry = mappingsIn; + } else { + entry = mappingsOut; + } + for ( ; entry->mDevices != AUDIO_DEVICE_NONE; entry++) { + allDevices = (audio_devices_t) (allDevices | entry->mDevices); + if (devices & entry->mDevices) { + if (!result.isEmpty()) { + result.append("|"); + } + result.append(entry->mString); + } + } + if (devices & ~allDevices) { + if (!result.isEmpty()) { + result.append("|"); + } + result.appendFormat("0x%X", devices & ~allDevices); + } + if (result.isEmpty()) { + result.append(entry->mString); + } + return result; +} + +String8 inputFlagsToString(audio_input_flags_t flags) +{ + static const struct mapping { + audio_input_flags_t mFlag; + const char * mString; + } mappings[] = { + AUDIO_INPUT_FLAG_FAST, "FAST", + AUDIO_INPUT_FLAG_HW_HOTWORD, "HW_HOTWORD", + AUDIO_INPUT_FLAG_NONE, "NONE", // must be last + }; + String8 result; + audio_input_flags_t allFlags = AUDIO_INPUT_FLAG_NONE; + const mapping *entry; + for (entry = mappings; entry->mFlag != AUDIO_INPUT_FLAG_NONE; entry++) { + allFlags = (audio_input_flags_t) (allFlags | entry->mFlag); + if (flags & entry->mFlag) { + if (!result.isEmpty()) { + result.append("|"); + } + result.append(entry->mString); + } + } + if (flags & ~allFlags) { + if (!result.isEmpty()) { + result.append("|"); + } + result.appendFormat("0x%X", flags & ~allFlags); + } + if (result.isEmpty()) { + result.append(entry->mString); + } + return result; +} + +String8 outputFlagsToString(audio_output_flags_t flags) +{ + static const struct mapping { + audio_output_flags_t mFlag; + const char * mString; + } mappings[] = { + AUDIO_OUTPUT_FLAG_DIRECT, "DIRECT", + AUDIO_OUTPUT_FLAG_PRIMARY, "PRIMARY", + AUDIO_OUTPUT_FLAG_FAST, "FAST", + AUDIO_OUTPUT_FLAG_DEEP_BUFFER, "DEEP_BUFFER", + AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD, "COMPRESS_OFFLOAD", + AUDIO_OUTPUT_FLAG_NON_BLOCKING, "NON_BLOCKING", + AUDIO_OUTPUT_FLAG_HW_AV_SYNC, "HW_AV_SYNC", + AUDIO_OUTPUT_FLAG_NONE, "NONE", // must be last + }; + String8 result; + audio_output_flags_t allFlags = AUDIO_OUTPUT_FLAG_NONE; + const mapping *entry; + for (entry = mappings; entry->mFlag != AUDIO_OUTPUT_FLAG_NONE; entry++) { + allFlags = (audio_output_flags_t) (allFlags | entry->mFlag); + if (flags & entry->mFlag) { + if (!result.isEmpty()) { + result.append("|"); + } + result.append(entry->mString); + } + } + if (flags & ~allFlags) { + if (!result.isEmpty()) { + result.append("|"); + } + result.appendFormat("0x%X", flags & ~allFlags); + } + if (result.isEmpty()) { + result.append(entry->mString); + } + return result; +} + +const char *sourceToString(audio_source_t source) +{ + switch (source) { + case AUDIO_SOURCE_DEFAULT: return "default"; + case AUDIO_SOURCE_MIC: return "mic"; + case AUDIO_SOURCE_VOICE_UPLINK: return "voice uplink"; + case AUDIO_SOURCE_VOICE_DOWNLINK: return "voice downlink"; + case AUDIO_SOURCE_VOICE_CALL: return "voice call"; + case AUDIO_SOURCE_CAMCORDER: return "camcorder"; + case AUDIO_SOURCE_VOICE_RECOGNITION: return "voice recognition"; + case AUDIO_SOURCE_VOICE_COMMUNICATION: return "voice communication"; + case AUDIO_SOURCE_REMOTE_SUBMIX: return "remote submix"; + case AUDIO_SOURCE_FM_TUNER: return "FM tuner"; + case AUDIO_SOURCE_HOTWORD: return "hotword"; + default: return "unknown"; + } +} + AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id, audio_devices_t outDevice, audio_devices_t inDevice, type_t type) : Thread(false /*canCallJava*/), @@ -338,7 +499,7 @@ AudioFlinger::ThreadBase::~ThreadBase() // do not lock the mutex in destructor releaseWakeLock_l(); if (mPowerManager != 0) { - sp<IBinder> binder = mPowerManager->asBinder(); + sp<IBinder> binder = IInterface::asBinder(mPowerManager); binder->unlinkToDeath(mDeathRecipient); } } @@ -577,20 +738,22 @@ void AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args __u bool locked = AudioFlinger::dumpTryLock(mLock); if (!locked) { - dprintf(fd, "thread %p maybe dead locked\n", this); + dprintf(fd, "thread %p may be deadlocked\n", this); } + dprintf(fd, " Thread name: %s\n", mThreadName); dprintf(fd, " I/O handle: %d\n", mId); dprintf(fd, " TID: %d\n", getTid()); dprintf(fd, " Standby: %s\n", mStandby ? "yes" : "no"); - dprintf(fd, " Sample rate: %u\n", mSampleRate); + dprintf(fd, " Sample rate: %u Hz\n", mSampleRate); dprintf(fd, " HAL frame count: %zu\n", mFrameCount); + dprintf(fd, " HAL format: 0x%x (%s)\n", mHALFormat, formatToString(mHALFormat)); dprintf(fd, " HAL buffer size: %u bytes\n", mBufferSize); - dprintf(fd, " Channel Count: %u\n", mChannelCount); - dprintf(fd, " Channel Mask: 0x%08x (%s)\n", mChannelMask, + dprintf(fd, " Channel count: %u\n", mChannelCount); + dprintf(fd, " Channel mask: 0x%08x (%s)\n", mChannelMask, channelMaskToString(mChannelMask, mType != RECORD).string()); - dprintf(fd, " Format: 0x%x (%s)\n", mHALFormat, formatToString(mHALFormat)); - dprintf(fd, " Frame size: %zu\n", mFrameSize); + dprintf(fd, " Format: 0x%x (%s)\n", mFormat, formatToString(mFormat)); + dprintf(fd, " Frame size: %zu bytes\n", mFrameSize); dprintf(fd, " Pending config events:"); size_t numConfig = mConfigEvents.size(); if (numConfig) { @@ -602,6 +765,9 @@ void AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args __u } else { dprintf(fd, " none\n"); } + dprintf(fd, " Output device: %#x (%s)\n", mOutDevice, devicesToString(mOutDevice).string()); + dprintf(fd, " Input device: %#x (%s)\n", mInDevice, devicesToString(mInDevice).string()); + dprintf(fd, " Audio source: %d (%s)\n", mAudioSource, sourceToString(mAudioSource)); if (locked) { mLock.unlock(); @@ -635,19 +801,19 @@ void AudioFlinger::ThreadBase::acquireWakeLock(int uid) String16 AudioFlinger::ThreadBase::getWakeLockTag() { switch (mType) { - case MIXER: - return String16("AudioMix"); - case DIRECT: - return String16("AudioDirectOut"); - case DUPLICATING: - return String16("AudioDup"); - case RECORD: - return String16("AudioIn"); - case OFFLOAD: - return String16("AudioOffload"); - default: - ALOG_ASSERT(false); - return String16("AudioUnknown"); + case MIXER: + return String16("AudioMix"); + case DIRECT: + return String16("AudioDirectOut"); + case DUPLICATING: + return String16("AudioDup"); + case RECORD: + return String16("AudioIn"); + case OFFLOAD: + return String16("AudioOffload"); + default: + ALOG_ASSERT(false); + return String16("AudioUnknown"); } } @@ -674,7 +840,7 @@ void AudioFlinger::ThreadBase::acquireWakeLock_l(int uid) if (status == NO_ERROR) { mWakeLockToken = binder; } - ALOGV("acquireWakeLock_l() %s status %d", mName, status); + ALOGV("acquireWakeLock_l() %s status %d", mThreadName, status); } } @@ -687,7 +853,7 @@ void AudioFlinger::ThreadBase::releaseWakeLock() void AudioFlinger::ThreadBase::releaseWakeLock_l() { if (mWakeLockToken != 0) { - ALOGV("releaseWakeLock_l() %s", mName); + ALOGV("releaseWakeLock_l() %s", mThreadName); if (mPowerManager != 0) { mPowerManager->releaseWakeLock(mWakeLockToken, 0, true /* FIXME force oneway contrary to .aidl */); @@ -708,7 +874,7 @@ void AudioFlinger::ThreadBase::getPowerManager_l() { sp<IBinder> binder = defaultServiceManager()->checkService(String16("power")); if (binder == 0) { - ALOGW("Thread %s cannot connect to the power manager service", mName); + ALOGW("Thread %s cannot connect to the power manager service", mThreadName); } else { mPowerManager = interface_cast<IPowerManager>(binder); binder->linkToDeath(mDeathRecipient); @@ -728,7 +894,7 @@ void AudioFlinger::ThreadBase::updateWakeLockUids_l(const SortedVector<int> &uid status_t status; status = mPowerManager->updateWakeLockUids(mWakeLockToken, uids.size(), uids.array(), true /* FIXME force oneway contrary to .aidl */); - ALOGV("acquireWakeLock_l() %s status %d", mName, status); + ALOGV("acquireWakeLock_l() %s status %d", mThreadName, status); } } @@ -912,7 +1078,7 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l( // mSinkBuffer is not guaranteed to be compatible with effect processing (PCM 16 stereo). if (mType == DIRECT) { ALOGW("createEffect_l() Cannot add effect %s on Direct output type thread %s", - desc->name, mName); + desc->name, mThreadName); lStatus = BAD_VALUE; goto Exit; } @@ -936,7 +1102,8 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l( case DUPLICATING: case RECORD: default: - ALOGW("createEffect_l() Cannot add global effect %s on thread %s", desc->name, mName); + ALOGW("createEffect_l() Cannot add global effect %s on thread %s", + desc->name, mThreadName); lStatus = BAD_VALUE; goto Exit; } @@ -1197,11 +1364,12 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge mScreenState(AudioFlinger::mScreenState), // index 0 is reserved for normal mixer's submix mFastTrackAvailMask(((1 << FastMixerState::kMaxFastTracks) - 1) & ~1), + mHwSupportsPause(false), mHwPaused(false), mFlushPending(false), // mLatchD, mLatchQ, mLatchDValid(false), mLatchQValid(false) { - snprintf(mName, kNameLength, "AudioOut_%X", id); - mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mName); + snprintf(mThreadName, kThreadNameLength, "AudioOut_%X", id); + mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mThreadName); // Assumes constructor is called by AudioFlinger with it's mLock held, but // it would be safer to explicitly pass initial masterVolume/masterMute as @@ -1224,15 +1392,12 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge readOutputParameters_l(); - // mStreamTypes[AUDIO_STREAM_CNT] is initialized by stream_type_t default constructor - // There is no AUDIO_STREAM_MIN, and ++ operator does not compile + // ++ operator does not compile for (audio_stream_type_t stream = AUDIO_STREAM_MIN; stream < AUDIO_STREAM_CNT; stream = (audio_stream_type_t) (stream + 1)) { mStreamTypes[stream].volume = mAudioFlinger->streamVolume_l(stream); mStreamTypes[stream].mute = mAudioFlinger->streamMute_l(stream); } - // mStreamTypes[AUDIO_STREAM_CNT] exists but isn't explicitly initialized here, - // because mAudioFlinger doesn't have one to copy from } AudioFlinger::PlaybackThread::~PlaybackThread() @@ -1317,7 +1482,10 @@ void AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& ar void AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args) { - dprintf(fd, "\nOutput thread %p:\n", this); + dprintf(fd, "\nOutput thread %p type %d (%s):\n", this, type(), threadTypeToString(type())); + + dumpBase(fd, args); + dprintf(fd, " Normal frame count: %zu\n", mNormalFrameCount); dprintf(fd, " Last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime)); dprintf(fd, " Total writes: %d\n", mNumWrites); @@ -1328,15 +1496,17 @@ void AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& dprintf(fd, " Mixer buffer: %p\n", mMixerBuffer); dprintf(fd, " Effect buffer: %p\n", mEffectBuffer); dprintf(fd, " Fast track availMask=%#x\n", mFastTrackAvailMask); - - dumpBase(fd, args); + AudioStreamOut *output = mOutput; + audio_output_flags_t flags = output != NULL ? output->flags : AUDIO_OUTPUT_FLAG_NONE; + String8 flagsAsString = outputFlagsToString(flags); + dprintf(fd, " AudioStreamOut: %p flags %#x (%s)\n", output, flags, flagsAsString.string()); } // Thread virtuals void AudioFlinger::PlaybackThread::onFirstRef() { - run(mName, ANDROID_PRIORITY_URGENT_AUDIO); + run(mThreadName, ANDROID_PRIORITY_URGENT_AUDIO); } // ThreadBase virtuals @@ -1380,9 +1550,10 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac ( (sharedBuffer != 0) ) || - // use case 2: callback handler and frame count is default or at least as large as HAL + // use case 2: frame count is default or at least as large as HAL ( - (tid != -1) && + // we formerly checked for a callback handler (non-0 tid), + // but that is no longer required for TRANSFER_OBTAIN mode ((frameCount == 0) || (frameCount >= mFrameCount)) ) @@ -1422,20 +1593,25 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac audio_is_linear_pcm(format), channelMask, sampleRate, mSampleRate, hasFastMixer(), tid, mFastTrackAvailMask); *flags &= ~IAudioFlinger::TRACK_FAST; - // For compatibility with AudioTrack calculation, buffer depth is forced - // to be at least 2 x the normal mixer frame count and cover audio hardware latency. - // This is probably too conservative, but legacy application code may depend on it. - // If you change this calculation, also review the start threshold which is related. + } + } + // For normal PCM streaming tracks, update minimum frame count. + // For compatibility with AudioTrack calculation, buffer depth is forced + // to be at least 2 x the normal mixer frame count and cover audio hardware latency. + // This is probably too conservative, but legacy application code may depend on it. + // If you change this calculation, also review the start threshold which is related. + if (!(*flags & IAudioFlinger::TRACK_FAST) + && audio_is_linear_pcm(format) && sharedBuffer == 0) { uint32_t latencyMs = mOutput->stream->get_latency(mOutput->stream); uint32_t minBufCount = latencyMs / ((1000 * mNormalFrameCount) / mSampleRate); if (minBufCount < 2) { minBufCount = 2; } - size_t minFrameCount = mNormalFrameCount * minBufCount; - if (frameCount < minFrameCount) { + size_t minFrameCount = + minBufCount * sourceFramesNeeded(sampleRate, mNormalFrameCount, mSampleRate); + if (frameCount < minFrameCount) { // including frameCount == 0 frameCount = minFrameCount; } - } } *pFrameCount = frameCount; @@ -1625,13 +1801,15 @@ status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track) if (track->isExternalTrack()) { TrackBase::track_state state = track->mState; mLock.unlock(); - status = AudioSystem::startOutput(mId, track->streamType(), track->sessionId()); + status = AudioSystem::startOutput(mId, track->streamType(), + (audio_session_t)track->sessionId()); mLock.lock(); // abort track was stopped/paused while we released the lock if (state != track->mState) { if (status == NO_ERROR) { mLock.unlock(); - AudioSystem::stopOutput(mId, track->streamType(), track->sessionId()); + AudioSystem::stopOutput(mId, track->streamType(), + (audio_session_t)track->sessionId()); mLock.lock(); } return INVALID_OPERATION; @@ -1848,6 +2026,35 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l() } } + mHwSupportsPause = false; + if (mOutput->flags & AUDIO_OUTPUT_FLAG_DIRECT) { + if (mOutput->stream->pause != NULL) { + if (mOutput->stream->resume != NULL) { + mHwSupportsPause = true; + } else { + ALOGW("direct output implements pause but not resume"); + } + } else if (mOutput->stream->resume != NULL) { + ALOGW("direct output implements resume but not pause"); + } + } + + if (mType == DUPLICATING && mMixerBufferEnabled && mEffectBufferEnabled) { + // For best precision, we use float instead of the associated output + // device format (typically PCM 16 bit). + + mFormat = AUDIO_FORMAT_PCM_FLOAT; + mFrameSize = mChannelCount * audio_bytes_per_sample(mFormat); + mBufferSize = mFrameSize * mFrameCount; + + // TODO: We currently use the associated output device channel mask and sample rate. + // (1) Perhaps use the ORed channel mask of all downstream MixerThreads + // (if a valid mask) to avoid premature downmix. + // (2) Perhaps use the maximum sample rate of all downstream MixerThreads + // instead of the output device sample rate to avoid loss of high frequency information. + // This may need to be updated as MixerThread/OutputTracks are added and not here. + } + // Calculate size of normal sink buffer relative to the HAL output buffer size double multiplier = 1.0; if (mType == MIXER && (kUseFastMixer == FastMixer_Static || @@ -2060,13 +2267,15 @@ void AudioFlinger::PlaybackThread::threadLoop_removeTracks( for (size_t i = 0 ; i < count ; i++) { const sp<Track>& track = tracksToRemove.itemAt(i); if (track->isExternalTrack()) { - AudioSystem::stopOutput(mId, track->streamType(), track->sessionId()); + AudioSystem::stopOutput(mId, track->streamType(), + (audio_session_t)track->sessionId()); #ifdef ADD_BATTERY_DATA // to track the speaker usage addBatteryData(IMediaPlayerService::kBatteryDataAudioFlingerStop); #endif if (track->isTerminated()) { - AudioSystem::releaseOutput(mId); + AudioSystem::releaseOutput(mId, track->streamType(), + (audio_session_t)track->sessionId()); } } } @@ -2180,7 +2389,13 @@ void AudioFlinger::PlaybackThread::threadLoop_drain() void AudioFlinger::PlaybackThread::threadLoop_exit() { - // Default implementation has nothing to do + { + Mutex::Autolock _l(mLock); + for (size_t i = 0; i < mTracks.size(); i++) { + sp<Track> track = mTracks[i]; + track->invalidate(); + } + } } /* @@ -2620,7 +2835,9 @@ bool AudioFlinger::PlaybackThread::threadLoop() } } else { + ATRACE_BEGIN("sleep"); usleep(sleepTime); + ATRACE_END(); } } @@ -2688,7 +2905,8 @@ status_t AudioFlinger::PlaybackThread::getTimestamp_l(AudioTimestamp& timestamp) if (mNormalSink != 0) { return mNormalSink->getTimestamp(timestamp); } - if ((mType == OFFLOAD || mType == DIRECT) && mOutput->stream->get_presentation_position) { + if ((mType == OFFLOAD || mType == DIRECT) + && mOutput != NULL && mOutput->stream->get_presentation_position) { uint64_t position64; int ret = mOutput->stream->get_presentation_position( mOutput->stream, &position64, ×tamp.mTime); @@ -2779,6 +2997,12 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud mNormalFrameCount); mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate); + if (type == DUPLICATING) { + // The Duplicating thread uses the AudioMixer and delivers data to OutputTracks + // (downstream MixerThreads) in DuplicatingThread::threadLoop_write(). + // Do not create or use mFastMixer, mOutputSink, mPipeSink, or mNormalSink. + return; + } // create an NBAIO sink for the HAL output stream, and negotiate mOutputSink = new AudioStreamOutSink(output->stream); size_t numCounterOffers = 0; @@ -2820,6 +3044,7 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud NBAIO_Format format = mOutputSink->format(); NBAIO_Format origformat = format; // adjust format to match that of the Fast Mixer + ALOGV("format changed from %d to %d", format.mFormat, fastMixerFormat); format.mFormat = fastMixerFormat; format.mFrameSize = audio_bytes_per_sample(format.mFormat) * format.mChannelCount; @@ -2999,8 +3224,10 @@ ssize_t AudioFlinger::MixerThread::threadLoop_write() #endif } state->mCommand = FastMixerState::MIX_WRITE; +#ifdef FAST_THREAD_STATISTICS mFastMixerDumpState.increaseSamplingN(mAudioFlinger->isLowRamDevice() ? - FastMixerDumpState::kSamplingNforLowRamDevice : FastMixerDumpState::kSamplingN); + FastThreadDumpState::kSamplingNforLowRamDevice : FastThreadDumpState::kSamplingN); +#endif sq->end(); sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED); if (kUseFastMixer == FastMixer_Dynamic) { @@ -3071,6 +3298,7 @@ void AudioFlinger::PlaybackThread::threadLoop_standby() mCallbackThread->setWriteBlocked(mWriteAckSequence); mCallbackThread->setDraining(mDrainSequence); } + mHwPaused = false; } void AudioFlinger::PlaybackThread::onAddNewTrack_l() @@ -3364,8 +3592,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac if (sr == mSampleRate) { desiredFrames = mNormalFrameCount; } else { - // +1 for rounding and +1 for additional sample needed for interpolation - desiredFrames = (mNormalFrameCount * sr) / mSampleRate + 1 + 1; + desiredFrames = sourceFramesNeeded(sr, mNormalFrameCount, mSampleRate); // add frames already consumed but not yet released by the resampler // because mAudioTrackServerProxy->framesReady() will include these frames desiredFrames += mAudioMixer->getUnreleasedFrames(track->name()); @@ -3383,6 +3610,23 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac } size_t framesReady = track->framesReady(); + if (ATRACE_ENABLED()) { + // I wish we had formatted trace names + char traceName[16]; + strcpy(traceName, "nRdy"); + int name = track->name(); + if (AudioMixer::TRACK0 <= name && + name < (int) (AudioMixer::TRACK0 + AudioMixer::MAX_NUM_TRACKS)) { + name -= AudioMixer::TRACK0; + traceName[4] = (name / 10) + '0'; + traceName[5] = (name % 10) + '0'; + } else { + traceName[4] = '?'; + traceName[5] = '?'; + } + traceName[6] = '\0'; + ATRACE_INT(traceName, framesReady); + } if ((framesReady >= minFrames) && track->isReady() && !track->isPaused() && !track->isTerminated()) { @@ -3983,6 +4227,9 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep { size_t count = mActiveTracks.size(); mixer_state mixerStatus = MIXER_IDLE; + bool doHwPause = false; + bool doHwResume = false; + bool flushPending = false; // find out which tracks need to be processed for (size_t i = 0; i < count; i++) { @@ -4001,10 +4248,37 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep sp<Track> l = mLatestActiveTrack.promote(); bool last = l.get() == track; + if (mHwSupportsPause && track->isPausing()) { + track->setPaused(); + if (last && !mHwPaused) { + doHwPause = true; + mHwPaused = true; + } + tracksToRemove->add(track); + } else if (track->isFlushPending()) { + track->flushAck(); + if (last) { + flushPending = true; + } + } else if (mHwSupportsPause && track->isResumePending()){ + track->resumeAck(); + if (last) { + if (mHwPaused) { + doHwResume = true; + mHwPaused = false; + } + } + } + // The first time a track is added we wait - // for all its buffers to be filled before processing it + // for all its buffers to be filled before processing it. + // Allow draining the buffer in case the client + // app does not call stop() and relies on underrun to stop: + // hence the test on (track->mRetryCount > 1). + // If retryCount<=1 then track is about to underrun and be removed. uint32_t minFrames; - if ((track->sharedBuffer() == 0) && !track->isStopping_1() && !track->isPausing()) { + if ((track->sharedBuffer() == 0) && !track->isStopping_1() && !track->isPausing() + && (track->mRetryCount > 1)) { minFrames = mNormalFrameCount; } else { minFrames = 1; @@ -4019,8 +4293,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep track->mFillingUpStatus = Track::FS_ACTIVE; // make sure processVolume_l() will apply new volume even if 0 mLeftVolFloat = mRightVolFloat = -1.0; - if (track->mState == TrackBase::RESUMING) { - track->mState = TrackBase::ACTIVE; + if (!mHwSupportsPause) { + track->resumeAck(); } } @@ -4031,6 +4305,10 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep track->mRetryCount = kMaxTrackRetriesDirect; mActiveTrack = t; mixerStatus = MIXER_TRACKS_READY; + if (usesHwAvSync() && mHwPaused) { + doHwResume = true; + mHwPaused = false; + } } } else { // clear effect chain input buffer if the last active track started underruns @@ -4059,9 +4337,6 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep track->mState = TrackBase::STOPPED; } if (track->isStopped()) { - if (track->mState == TrackBase::FLUSHED) { - flushHw_l(); - } track->reset(); } tracksToRemove->add(track); @@ -4078,11 +4353,39 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep android_atomic_or(CBLK_DISABLED, &cblk->mFlags); } else if (last) { mixerStatus = MIXER_TRACKS_ENABLED; + if (usesHwAvSync() && !mHwPaused && !mStandby) { + doHwPause = true; + mHwPaused = true; + } } } } } + // if an active track did not command a flush, check for pending flush on stopped tracks + if (!flushPending) { + for (size_t i = 0; i < mTracks.size(); i++) { + if (mTracks[i]->isFlushPending()) { + mTracks[i]->flushAck(); + flushPending = true; + } + } + } + + // make sure the pause/flush/resume sequence is executed in the right order. + // If a flush is pending and a track is active but the HW is not paused, force a HW pause + // before flush and then resume HW. This can happen in case of pause/flush/resume + // if resume is received before pause is executed. + if (mHwSupportsPause && !mStandby && + (doHwPause || (flushPending && !mHwPaused && (count != 0)))) { + mOutput->stream->pause(mOutput->stream); + } + if (flushPending) { + flushHw_l(); + } + if (mHwSupportsPause && !mStandby && doHwResume) { + mOutput->stream->resume(mOutput->stream); + } // remove all the tracks that need to be... removeTracks_l(*tracksToRemove); @@ -4115,6 +4418,11 @@ void AudioFlinger::DirectOutputThread::threadLoop_mix() void AudioFlinger::DirectOutputThread::threadLoop_sleepTime() { + // do not write to HAL when paused + if (mHwPaused || (usesHwAvSync() && mStandby)) { + sleepTime = idleSleepTime; + return; + } if (sleepTime == 0) { if (mMixerStatus == MIXER_TRACKS_ENABLED) { sleepTime = activeSleepTime; @@ -4127,6 +4435,38 @@ void AudioFlinger::DirectOutputThread::threadLoop_sleepTime() } } +void AudioFlinger::DirectOutputThread::threadLoop_exit() +{ + { + Mutex::Autolock _l(mLock); + bool flushPending = false; + for (size_t i = 0; i < mTracks.size(); i++) { + if (mTracks[i]->isFlushPending()) { + mTracks[i]->flushAck(); + flushPending = true; + } + } + if (flushPending) { + flushHw_l(); + } + } + PlaybackThread::threadLoop_exit(); +} + +// must be called with thread mutex locked +bool AudioFlinger::DirectOutputThread::shouldStandby_l() +{ + bool trackPaused = false; + + // do not put the HAL in standby when paused. AwesomePlayer clear the offloaded AudioTrack + // after a timeout and we will enter standby then. + if (mTracks.size() > 0) { + trackPaused = mTracks[mTracks.size() - 1]->isPaused(); + } + + return !mStandby && !(trackPaused || (usesHwAvSync() && mHwPaused)); +} + // getTrackName_l() must be called with ThreadBase::mLock held int AudioFlinger::DirectOutputThread::getTrackName_l(audio_channel_mask_t channelMask __unused, audio_format_t format __unused, int sessionId __unused) @@ -4236,8 +4576,10 @@ void AudioFlinger::DirectOutputThread::cacheParameters_l() void AudioFlinger::DirectOutputThread::flushHw_l() { - if (mOutput->stream->flush != NULL) + if (mOutput->stream->flush != NULL) { mOutput->stream->flush(mOutput->stream); + } + mHwPaused = false; } // ---------------------------------------------------------------------------- @@ -4346,8 +4688,6 @@ void AudioFlinger::AsyncCallbackThread::resetDraining() AudioFlinger::OffloadThread::OffloadThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, audio_io_handle_t id, uint32_t device) : DirectOutputThread(audioFlinger, output, id, device, OFFLOAD), - mHwPaused(false), - mFlushPending(false), mPausedBytesRemaining(0) { //FIXME: mStandby should be set to true by ThreadBase constructor @@ -4584,21 +4924,6 @@ bool AudioFlinger::OffloadThread::waitingAsyncCallback_l() return false; } -// must be called with thread mutex locked -bool AudioFlinger::OffloadThread::shouldStandby_l() -{ - bool trackPaused = false; - - // do not put the HAL in standby when paused. AwesomePlayer clear the offloaded AudioTrack - // after a timeout and we will enter standby then. - if (mTracks.size() > 0) { - trackPaused = mTracks[mTracks.size() - 1]->isPaused(); - } - - return !mStandby && !trackPaused; -} - - bool AudioFlinger::OffloadThread::waitingAsyncCallback() { Mutex::Autolock _l(mLock); @@ -4613,7 +4938,6 @@ void AudioFlinger::OffloadThread::flushHw_l() mBytesRemaining = 0; mPausedWriteLength = 0; mPausedBytesRemaining = 0; - mHwPaused = false; if (mUseAsyncWrite) { // discard any pending drain or write ack by incrementing sequence @@ -4661,7 +4985,11 @@ void AudioFlinger::DuplicatingThread::threadLoop_mix() if (outputsReady(outputTracks)) { mAudioMixer->process(AudioBufferProvider::kInvalidPTS); } else { - memset(mSinkBuffer, 0, mSinkBufferSize); + if (mMixerBufferValid) { + memset(mMixerBuffer, 0, mMixerBufferSize); + } else { + memset(mSinkBuffer, 0, mSinkBufferSize); + } } sleepTime = 0; writeFrames = mNormalFrameCount; @@ -4692,15 +5020,7 @@ void AudioFlinger::DuplicatingThread::threadLoop_sleepTime() ssize_t AudioFlinger::DuplicatingThread::threadLoop_write() { for (size_t i = 0; i < outputTracks.size(); i++) { - // We convert the duplicating thread format to AUDIO_FORMAT_PCM_16_BIT - // for delivery downstream as needed. This in-place conversion is safe as - // AUDIO_FORMAT_PCM_16_BIT is smaller than any other supported format - // (AUDIO_FORMAT_PCM_8_BIT is not allowed here). - if (mFormat != AUDIO_FORMAT_PCM_16_BIT) { - memcpy_by_audio_format(mSinkBuffer, AUDIO_FORMAT_PCM_16_BIT, - mSinkBuffer, mFormat, writeFrames * mChannelCount); - } - outputTracks[i]->write(reinterpret_cast<int16_t*>(mSinkBuffer), writeFrames); + outputTracks[i]->write(mSinkBuffer, writeFrames); } mStandby = false; return (ssize_t)mSinkBufferSize; @@ -4727,25 +5047,26 @@ void AudioFlinger::DuplicatingThread::clearOutputTracks() void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread) { Mutex::Autolock _l(mLock); - // FIXME explain this formula - size_t frameCount = (3 * mNormalFrameCount * mSampleRate) / thread->sampleRate(); - // OutputTrack is forced to AUDIO_FORMAT_PCM_16_BIT regardless of mFormat - // due to current usage case and restrictions on the AudioBufferProvider. - // Actual buffer conversion is done in threadLoop_write(). - // - // TODO: This may change in the future, depending on multichannel - // (and non int16_t*) support on AF::PlaybackThread::OutputTrack - OutputTrack *outputTrack = new OutputTrack(thread, + // The downstream MixerThread consumes thread->frameCount() amount of frames per mix pass. + // Adjust for thread->sampleRate() to determine minimum buffer frame count. + // Then triple buffer because Threads do not run synchronously and may not be clock locked. + const size_t frameCount = + 3 * sourceFramesNeeded(mSampleRate, thread->frameCount(), thread->sampleRate()); + // TODO: Consider asynchronous sample rate conversion to handle clock disparity + // from different OutputTracks and their associated MixerThreads (e.g. one may + // nearly empty and the other may be dropping data). + + sp<OutputTrack> outputTrack = new OutputTrack(thread, this, mSampleRate, - AUDIO_FORMAT_PCM_16_BIT, + mFormat, mChannelMask, frameCount, IPCThreadState::self()->getCallingUid()); if (outputTrack->cblk() != NULL) { - thread->setStreamVolume(AUDIO_STREAM_CNT, 1.0f); + thread->setStreamVolume(AUDIO_STREAM_PATCH, 1.0f); mOutputTracks.add(outputTrack); - ALOGV("addOutputTrack() track %p, on thread %p", outputTrack, thread); + ALOGV("addOutputTrack() track %p, on thread %p", outputTrack.get(), thread); updateWaitTime_l(); } } @@ -4846,8 +5167,8 @@ AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, // mFastCaptureNBLogWriter , mFastTrackAvail(false) { - snprintf(mName, kNameLength, "AudioIn_%X", id); - mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mName); + snprintf(mThreadName, kThreadNameLength, "AudioIn_%X", id); + mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mThreadName); readInputParameters_l(); @@ -4988,7 +5309,7 @@ AudioFlinger::RecordThread::~RecordThread() void AudioFlinger::RecordThread::onFirstRef() { - run(mName, PRIORITY_URGENT_AUDIO); + run(mThreadName, PRIORITY_URGENT_AUDIO); } bool AudioFlinger::RecordThread::threadLoop() @@ -5029,7 +5350,9 @@ reacquire_wakelock: // sleep with mutex unlocked if (sleepUs > 0) { + ATRACE_BEGIN("sleep"); usleep(sleepUs); + ATRACE_END(); sleepUs = 0; } @@ -5173,7 +5496,8 @@ reacquire_wakelock: state->mCommand = FastCaptureState::READ_WRITE; #if 0 // FIXME mFastCaptureDumpState.increaseSamplingN(mAudioFlinger->isLowRamDevice() ? - FastCaptureDumpState::kSamplingNforLowRamDevice : FastMixerDumpState::kSamplingN); + FastThreadDumpState::kSamplingNforLowRamDevice : + FastThreadDumpState::kSamplingN); #endif didModify = true; } @@ -5321,8 +5645,8 @@ reacquire_wakelock: upmix_to_stereo_i16_from_mono_i16((int16_t *)dst, (const int16_t *)src, part1); } else { - downmix_to_mono_i16_from_stereo_i16((int16_t *)dst, (const int16_t *)src, - part1); + downmix_to_mono_i16_from_stereo_i16((int16_t *)dst, + (const int16_t *)src, part1); } dst += part1 * activeTrack->mFrameSize; front += part1; @@ -5833,15 +6157,17 @@ void AudioFlinger::RecordThread::dumpInternals(int fd, const Vector<String16>& a { dprintf(fd, "\nInput thread %p:\n", this); - if (mActiveTracks.size() > 0) { - dprintf(fd, " Buffer size: %zu bytes\n", mBufferSize); - } else { + dumpBase(fd, args); + + if (mActiveTracks.size() == 0) { dprintf(fd, " No active record clients\n"); } dprintf(fd, " Fast capture thread: %s\n", hasFastCapture() ? "yes" : "no"); dprintf(fd, " Fast track available: %s\n", mFastTrackAvail ? "yes" : "no"); - dumpBase(fd, args); + // Make a non-atomic copy of fast capture dump state so it won't change underneath us + const FastCaptureDumpState copy(mFastCaptureDumpState); + copy.dump(fd); } void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args __unused) @@ -6306,4 +6632,4 @@ void AudioFlinger::RecordThread::getAudioPortConfig(struct audio_port_config *co config->ext.mix.usecase.source = mAudioSource; } -}; // namespace android +} // namespace android diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index bb9aa18..d600ea9 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -32,6 +32,8 @@ public: OFFLOAD // Thread class is OffloadThread }; + static const char *threadTypeToString(type_t type); + ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id, audio_devices_t outDevice, audio_devices_t inDevice, type_t type); virtual ~ThreadBase(); @@ -406,6 +408,7 @@ protected: audio_channel_mask_t mChannelMask; uint32_t mChannelCount; size_t mFrameSize; + // not HAL frame size, this is for output sink (to pipe to fast mixer) audio_format_t mFormat; // Source format for Recording and // Sink format for Playback. // Sink format may be different than @@ -424,13 +427,13 @@ protected: bool mStandby; // Whether thread is currently in standby. audio_devices_t mOutDevice; // output device audio_devices_t mInDevice; // input device - audio_source_t mAudioSource; // (see audio.h, audio_source_t) + audio_source_t mAudioSource; const audio_io_handle_t mId; Vector< sp<EffectChain> > mEffectChains; - static const int kNameLength = 16; // prctl(PR_SET_NAME) limit - char mName[kNameLength]; + static const int kThreadNameLength = 16; // prctl(PR_SET_NAME) limit + char mThreadName[kThreadNameLength]; // guaranteed NUL-terminated sp<IPowerManager> mPowerManager; sp<IBinder> mWakeLockToken; const sp<PMDeathRecipient> mDeathRecipient; @@ -710,6 +713,9 @@ protected: audio_patch_handle_t *handle); virtual status_t releaseAudioPatch_l(const audio_patch_handle_t handle); + bool usesHwAvSync() const { return (mType == DIRECT) && (mOutput != NULL) && + (mOutput->flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC); } + private: friend class AudioFlinger; // for numerous @@ -727,9 +733,7 @@ private: void dumpTracks(int fd, const Vector<String16>& args); SortedVector< sp<Track> > mTracks; - // mStreamTypes[] uses 1 additional stream type internally for the OutputTrack used by - // DuplicatingThread - stream_type_t mStreamTypes[AUDIO_STREAM_CNT + 1]; + stream_type_t mStreamTypes[AUDIO_STREAM_CNT]; AudioStreamOut *mOutput; float mMasterVolume; @@ -811,7 +815,9 @@ public: protected: // accessed by both binder threads and within threadLoop(), lock on mutex needed unsigned mFastTrackAvailMask; // bit i set if fast track [i] is available - + bool mHwSupportsPause; + bool mHwPaused; + bool mFlushPending; private: // timestamp latch: // D input is written by threadLoop_write while mutex is unlocked, and read while locked @@ -912,6 +918,8 @@ protected: virtual mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove); virtual void threadLoop_mix(); virtual void threadLoop_sleepTime(); + virtual void threadLoop_exit(); + virtual bool shouldStandby_l(); // volumes last sent to audio HAL with stream->set_volume() float mLeftVolFloat; @@ -942,12 +950,9 @@ protected: virtual bool waitingAsyncCallback(); virtual bool waitingAsyncCallback_l(); - virtual bool shouldStandby_l(); virtual void onAddNewTrack_l(); private: - bool mHwPaused; - bool mFlushPending; size_t mPausedWriteLength; // length in bytes of write interrupted by pause size_t mPausedBytesRemaining; // bytes still waiting in mixbuffer after resume wp<Track> mPreviousTrack; // used to detect track switch @@ -1165,7 +1170,8 @@ private: const sp<MemoryDealer> mReadOnlyHeap; // one-time initialization, no locks required - sp<FastCapture> mFastCapture; // non-0 if there is also a fast capture + sp<FastCapture> mFastCapture; // non-0 if there is also + // a fast capture // FIXME audio watchdog thread // contents are not guaranteed to be consistent, no locks required diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index 7d8d4c8..38667b9 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -20,6 +20,7 @@ //#define LOG_NDEBUG 0 #include "Configuration.h" +#include <linux/futex.h> #include <math.h> #include <sys/syscall.h> #include <utils/Log.h> @@ -443,8 +444,6 @@ AudioFlinger::PlaybackThread::Track::Track( // this means we are potentially denying other more important fast tracks from // being created. It would be better to allocate the index dynamically. mFastIndex = i; - // Read the initial underruns because this field is never cleared by the fast mixer - mObservedUnderruns = thread->getFastTrackUnderruns(i); thread->mFastTrackAvailMask &= ~(1 << i); } } @@ -491,7 +490,7 @@ void AudioFlinger::PlaybackThread::Track::destroy() wasActive = playbackThread->destroyTrack_l(this); } if (isExternalTrack() && !wasActive) { - AudioSystem::releaseOutput(mThreadIoHandle); + AudioSystem::releaseOutput(mThreadIoHandle, mStreamType, (audio_session_t)mSessionId); } } } @@ -611,15 +610,16 @@ status_t AudioFlinger::PlaybackThread::Track::getNextBuffer( // ExtendedAudioBufferProvider interface -// Note that framesReady() takes a mutex on the control block using tryLock(). -// This could result in priority inversion if framesReady() is called by the normal mixer, -// as the normal mixer thread runs at lower -// priority than the client's callback thread: there is a short window within framesReady() -// during which the normal mixer could be preempted, and the client callback would block. -// Another problem can occur if framesReady() is called by the fast mixer: -// the tryLock() could block for up to 1 ms, and a sequence of these could delay fast mixer. -// FIXME Replace AudioTrackShared control block implementation by a non-blocking FIFO queue. +// framesReady() may return an approximation of the number of frames if called +// from a different thread than the one calling Proxy->obtainBuffer() and +// Proxy->releaseBuffer(). Also note there is no mutual exclusion in the +// AudioTrackServerProxy so be especially careful calling with FastTracks. size_t AudioFlinger::PlaybackThread::Track::framesReady() const { + if (mSharedBuffer != 0 && (isStopped() || isStopping())) { + // Static tracks return zero frames immediately upon stopping (for FastTracks). + // The remainder of the buffer is not drained. + return 0; + } return mAudioTrackServerProxy->framesReady(); } @@ -692,6 +692,12 @@ status_t AudioFlinger::PlaybackThread::Track::start(AudioSystem::sync_event_t ev } PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); + if (isFastTrack()) { + // refresh fast track underruns on start because that field is never cleared + // by the fast mixer; furthermore, the same track can be recycled, i.e. start + // after stop. + mObservedUnderruns = playbackThread->getFastTrackUnderruns(mFastIndex); + } status = playbackThread->addTrack_l(this); if (status == INVALID_OPERATION || status == PERMISSION_DENIED) { triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE); @@ -822,12 +828,11 @@ void AudioFlinger::PlaybackThread::Track::flush() // this will be done by prepareTracks_l() when the track is stopped. // prepareTracks_l() will see mState == FLUSHED, then // remove from active track list, reset(), and trigger presentation complete + if (isDirect()) { + mFlushHwPending = true; + } if (playbackThread->mActiveTracks.indexOf(this) < 0) { reset(); - if (thread->type() == ThreadBase::DIRECT) { - DirectOutputThread *t = (DirectOutputThread *)playbackThread; - t->flushHw_l(); - } } } // Prevent flush being lost if the track is flushed and then resumed @@ -840,7 +845,7 @@ void AudioFlinger::PlaybackThread::Track::flush() // must be called with thread lock held void AudioFlinger::PlaybackThread::Track::flushAck() { - if (!isOffloaded()) + if (!isOffloaded() && !isDirect()) return; mFlushHwPending = false; @@ -1657,8 +1662,9 @@ AudioFlinger::PlaybackThread::OutputTrack::OutputTrack( audio_channel_mask_t channelMask, size_t frameCount, int uid) - : Track(playbackThread, NULL, AUDIO_STREAM_CNT, sampleRate, format, channelMask, frameCount, - NULL, 0, 0, uid, IAudioFlinger::TRACK_DEFAULT, TYPE_OUTPUT), + : Track(playbackThread, NULL, AUDIO_STREAM_PATCH, + sampleRate, format, channelMask, frameCount, + NULL, 0, 0, uid, IAudioFlinger::TRACK_DEFAULT, TYPE_OUTPUT), mActive(false), mSourceThread(sourceThread), mClientProxy(NULL) { @@ -1709,36 +1715,18 @@ void AudioFlinger::PlaybackThread::OutputTrack::stop() mActive = false; } -bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t frames) +bool AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t frames) { Buffer *pInBuffer; Buffer inBuffer; - uint32_t channelCount = mChannelCount; bool outputBufferFull = false; inBuffer.frameCount = frames; - inBuffer.i16 = data; + inBuffer.raw = data; uint32_t waitTimeLeftMs = mSourceThread->waitTimeMs(); if (!mActive && frames != 0) { - start(); - sp<ThreadBase> thread = mThread.promote(); - if (thread != 0) { - MixerThread *mixerThread = (MixerThread *)thread.get(); - if (mFrameCount > frames) { - if (mBufferQueue.size() < kMaxOverFlowBuffers) { - uint32_t startFrames = (mFrameCount - frames); - pInBuffer = new Buffer; - pInBuffer->mBuffer = new int16_t[startFrames * channelCount]; - pInBuffer->frameCount = startFrames; - pInBuffer->i16 = pInBuffer->mBuffer; - memset(pInBuffer->raw, 0, startFrames * channelCount * sizeof(int16_t)); - mBufferQueue.add(pInBuffer); - } else { - ALOGW("OutputTrack::write() %p no more buffers in queue", this); - } - } - } + (void) start(); } while (waitTimeLeftMs) { @@ -1773,20 +1761,20 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount : pInBuffer->frameCount; - memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channelCount * sizeof(int16_t)); + memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * mFrameSize); Proxy::Buffer buf; buf.mFrameCount = outFrames; buf.mRaw = NULL; mClientProxy->releaseBuffer(&buf); pInBuffer->frameCount -= outFrames; - pInBuffer->i16 += outFrames * channelCount; + pInBuffer->raw = (int8_t *)pInBuffer->raw + outFrames * mFrameSize; mOutBuffer.frameCount -= outFrames; - mOutBuffer.i16 += outFrames * channelCount; + mOutBuffer.raw = (int8_t *)mOutBuffer.raw + outFrames * mFrameSize; if (pInBuffer->frameCount == 0) { if (mBufferQueue.size()) { mBufferQueue.removeAt(0); - delete [] pInBuffer->mBuffer; + free(pInBuffer->mBuffer); delete pInBuffer; ALOGV("OutputTrack::write() %p thread %p released overflow buffer %d", this, mThread.unsafe_get(), mBufferQueue.size()); @@ -1802,11 +1790,10 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr if (thread != 0 && !thread->standby()) { if (mBufferQueue.size() < kMaxOverFlowBuffers) { pInBuffer = new Buffer; - pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channelCount]; + pInBuffer->mBuffer = malloc(inBuffer.frameCount * mFrameSize); pInBuffer->frameCount = inBuffer.frameCount; - pInBuffer->i16 = pInBuffer->mBuffer; - memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channelCount * - sizeof(int16_t)); + pInBuffer->raw = pInBuffer->mBuffer; + memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * mFrameSize); mBufferQueue.add(pInBuffer); ALOGV("OutputTrack::write() %p thread %p adding overflow buffer %d", this, mThread.unsafe_get(), mBufferQueue.size()); @@ -1817,23 +1804,10 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr } } - // Calling write() with a 0 length buffer, means that no more data will be written: - // If no more buffers are pending, fill output track buffer to make sure it is started - // by output mixer. - if (frames == 0 && mBufferQueue.size() == 0) { - // FIXME borken, replace by getting framesReady() from proxy - size_t user = 0; // was mCblk->user - if (user < mFrameCount) { - frames = mFrameCount - user; - pInBuffer = new Buffer; - pInBuffer->mBuffer = new int16_t[frames * channelCount]; - pInBuffer->frameCount = frames; - pInBuffer->i16 = pInBuffer->mBuffer; - memset(pInBuffer->raw, 0, frames * channelCount * sizeof(int16_t)); - mBufferQueue.add(pInBuffer); - } else if (mActive) { - stop(); - } + // Calling write() with a 0 length buffer means that no more data will be written: + // We rely on stop() to set the appropriate flags to allow the remaining frames to play out. + if (frames == 0 && mBufferQueue.size() == 0 && mActive) { + stop(); } return outputBufferFull; @@ -1859,7 +1833,7 @@ void AudioFlinger::PlaybackThread::OutputTrack::clearBufferQueue() for (size_t i = 0; i < size; i++) { Buffer *pBuffer = mBufferQueue.itemAt(i); - delete [] pBuffer->mBuffer; + free(pBuffer->mBuffer); delete pBuffer; } mBufferQueue.clear(); @@ -1873,7 +1847,8 @@ AudioFlinger::PlaybackThread::PatchTrack::PatchTrack(PlaybackThread *playbackThr size_t frameCount, void *buffer, IAudioFlinger::track_flags_t flags) - : Track(playbackThread, NULL, AUDIO_STREAM_CNT, sampleRate, format, channelMask, frameCount, + : Track(playbackThread, NULL, AUDIO_STREAM_PATCH, + sampleRate, format, channelMask, frameCount, buffer, 0, 0, getuid(), flags, TYPE_PATCH), mProxy(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, true, true)) { @@ -2211,4 +2186,4 @@ void AudioFlinger::RecordThread::PatchRecord::releaseBuffer(Proxy::Buffer* buffe mProxy->releaseBuffer(buffer); } -}; // namespace android +} // namespace android diff --git a/services/audioflinger/test-resample.cpp b/services/audioflinger/test-resample.cpp index 84a655a..7893778 100644 --- a/services/audioflinger/test-resample.cpp +++ b/services/audioflinger/test-resample.cpp @@ -427,6 +427,14 @@ int main(int argc, char* argv[]) { printf("quality: %d channels: %d msec: %" PRId64 " Mfrms/s: %.2lf\n", quality, channels, time/1000000, output_frames * looplimit / (time / 1e9) / 1e6); resampler->reset(); + + // TODO fix legacy bug: reset does not clear buffers. + // delete and recreate resampler here. + delete resampler; + resampler = AudioResampler::create(format, channels, + output_freq, quality); + resampler->setSampleRate(input_freq); + resampler->setVolume(AudioResampler::UNITY_GAIN_FLOAT, AudioResampler::UNITY_GAIN_FLOAT); } memset(output_vaddr, 0, output_size); diff --git a/services/audioflinger/tests/Android.mk b/services/audioflinger/tests/Android.mk index 7bba05b..8604ef5 100644 --- a/services/audioflinger/tests/Android.mk +++ b/services/audioflinger/tests/Android.mk @@ -10,19 +10,10 @@ LOCAL_SHARED_LIBRARIES := \ liblog \ libutils \ libcutils \ - libstlport \ libaudioutils \ libaudioresampler -LOCAL_STATIC_LIBRARIES := \ - libgtest \ - libgtest_main - LOCAL_C_INCLUDES := \ - bionic \ - bionic/libstdc++/include \ - external/gtest/include \ - external/stlport/stlport \ $(call include-path-for, audio-utils) \ frameworks/av/services/audioflinger @@ -32,21 +23,24 @@ LOCAL_SRC_FILES := \ LOCAL_MODULE := resampler_tests LOCAL_MODULE_TAGS := tests -include $(BUILD_EXECUTABLE) +include $(BUILD_NATIVE_TEST) # # audio mixer test tool # include $(CLEAR_VARS) +# Clang++ aborts on AudioMixer.cpp, +# b/18373866, "do not know how to split this operator." +ifeq ($(filter $(TARGET_ARCH),arm arm64),$(TARGET_ARCH)) + LOCAL_CLANG := false +endif + LOCAL_SRC_FILES:= \ test-mixer.cpp \ ../AudioMixer.cpp.arm \ LOCAL_C_INCLUDES := \ - bionic \ - bionic/libstdc++/include \ - external/stlport/stlport \ $(call include-path-for, audio-effects) \ $(call include-path-for, audio-utils) \ frameworks/av/services/audioflinger @@ -55,7 +49,6 @@ LOCAL_STATIC_LIBRARIES := \ libsndfile LOCAL_SHARED_LIBRARIES := \ - libstlport \ libeffects \ libnbaio \ libcommon_time_client \ @@ -70,4 +63,6 @@ LOCAL_MODULE:= test-mixer LOCAL_MODULE_TAGS := optional +LOCAL_CXX_STL := libc++ + include $(BUILD_EXECUTABLE) diff --git a/services/audioflinger/tests/build_and_run_all_unit_tests.sh b/services/audioflinger/tests/build_and_run_all_unit_tests.sh index 2c453b0..7f4d456 100755 --- a/services/audioflinger/tests/build_and_run_all_unit_tests.sh +++ b/services/audioflinger/tests/build_and_run_all_unit_tests.sh @@ -15,7 +15,7 @@ mm echo "waiting for device" adb root && adb wait-for-device remount adb push $OUT/system/lib/libaudioresampler.so /system/lib -adb push $OUT/system/bin/resampler_tests /system/bin +adb push $OUT/data/nativetest/resampler_tests /system/bin sh $ANDROID_BUILD_TOP/frameworks/av/services/audioflinger/tests/run_all_unit_tests.sh diff --git a/services/audioflinger/tests/mixer_to_wav_tests.sh b/services/audioflinger/tests/mixer_to_wav_tests.sh index e60e6d5..d0482a1 100755 --- a/services/audioflinger/tests/mixer_to_wav_tests.sh +++ b/services/audioflinger/tests/mixer_to_wav_tests.sh @@ -60,7 +60,7 @@ function createwav() { fi # Test: -# process__genericResampling +# process__genericResampling with mixed integer and float track input # track__Resample / track__genericResample adb shell test-mixer $1 -s 48000 \ -o /sdcard/tm48000grif.wav \ |