summaryrefslogtreecommitdiffstats
path: root/services/audioflinger
diff options
context:
space:
mode:
Diffstat (limited to 'services/audioflinger')
-rw-r--r--services/audioflinger/Android.mk41
-rw-r--r--services/audioflinger/AudioFlinger.cpp105
-rw-r--r--services/audioflinger/AudioFlinger.h8
-rw-r--r--services/audioflinger/AudioMixer.cpp52
-rw-r--r--services/audioflinger/AudioMixer.h28
-rw-r--r--services/audioflinger/AudioMixerOps.h9
-rw-r--r--services/audioflinger/AudioResampler.cpp5
-rw-r--r--services/audioflinger/AudioResampler.h7
-rw-r--r--services/audioflinger/AudioResamplerCubic.cpp3
-rw-r--r--services/audioflinger/AudioResamplerCubic.h2
-rw-r--r--services/audioflinger/AudioResamplerDyn.cpp2
-rw-r--r--services/audioflinger/AudioResamplerDyn.h2
-rw-r--r--services/audioflinger/AudioResamplerFirGen.h13
-rw-r--r--services/audioflinger/AudioResamplerFirOps.h4
-rw-r--r--services/audioflinger/AudioResamplerFirProcess.h48
-rw-r--r--services/audioflinger/AudioResamplerFirProcessNeon.h1137
-rw-r--r--services/audioflinger/AudioResamplerSinc.cpp265
-rw-r--r--services/audioflinger/AudioResamplerSinc.h2
-rw-r--r--services/audioflinger/AudioResamplerSincDown.h131
-rw-r--r--services/audioflinger/AudioResamplerSincUp.h131
-rw-r--r--services/audioflinger/Configuration.h5
-rw-r--r--services/audioflinger/Effects.cpp2
-rw-r--r--services/audioflinger/FastCapture.cpp146
-rw-r--r--services/audioflinger/FastCapture.h39
-rw-r--r--services/audioflinger/FastCaptureDumpState.cpp53
-rw-r--r--services/audioflinger/FastCaptureDumpState.h42
-rw-r--r--services/audioflinger/FastCaptureState.cpp15
-rw-r--r--services/audioflinger/FastCaptureState.h14
-rw-r--r--services/audioflinger/FastMixer.cpp464
-rw-r--r--services/audioflinger/FastMixer.h51
-rw-r--r--services/audioflinger/FastMixerDumpState.cpp199
-rw-r--r--services/audioflinger/FastMixerDumpState.h27
-rw-r--r--services/audioflinger/FastMixerState.cpp15
-rw-r--r--services/audioflinger/FastMixerState.h3
-rw-r--r--services/audioflinger/FastThread.cpp272
-rw-r--r--services/audioflinger/FastThread.h67
-rw-r--r--services/audioflinger/FastThreadDumpState.cpp58
-rw-r--r--services/audioflinger/FastThreadDumpState.h72
-rw-r--r--services/audioflinger/FastThreadState.cpp23
-rw-r--r--services/audioflinger/FastThreadState.h37
-rw-r--r--services/audioflinger/PatchPanel.cpp4
-rw-r--r--services/audioflinger/PlaybackTracks.h4
-rw-r--r--services/audioflinger/StateQueue.cpp2
-rw-r--r--services/audioflinger/Threads.cpp552
-rw-r--r--services/audioflinger/Threads.h28
-rw-r--r--services/audioflinger/Tracks.cpp109
-rw-r--r--services/audioflinger/test-resample.cpp8
-rw-r--r--services/audioflinger/tests/Android.mk23
-rwxr-xr-xservices/audioflinger/tests/build_and_run_all_unit_tests.sh2
-rwxr-xr-xservices/audioflinger/tests/mixer_to_wav_tests.sh2
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 = &current->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 = &current->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 = &current->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 = &current->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, &timestamp.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 \