diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:05:43 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:05:43 -0800 |
commit | f013e1afd1e68af5e3b868c26a653bbfb39538f8 (patch) | |
tree | 7ad6c8fd9c7b55f4b4017171dec1cb760bbd26bf /libs/audioflinger | |
parent | e70cfafe580c6f2994c4827cd8a534aabf3eb05c (diff) | |
download | frameworks_base-f013e1afd1e68af5e3b868c26a653bbfb39538f8.zip frameworks_base-f013e1afd1e68af5e3b868c26a653bbfb39538f8.tar.gz frameworks_base-f013e1afd1e68af5e3b868c26a653bbfb39538f8.tar.bz2 |
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'libs/audioflinger')
-rw-r--r-- | libs/audioflinger/A2dpAudioInterface.cpp | 186 | ||||
-rw-r--r-- | libs/audioflinger/A2dpAudioInterface.h | 107 | ||||
-rw-r--r-- | libs/audioflinger/Android.mk | 7 | ||||
-rw-r--r-- | libs/audioflinger/AudioDumpInterface.cpp | 49 | ||||
-rw-r--r-- | libs/audioflinger/AudioDumpInterface.h | 53 | ||||
-rw-r--r-- | libs/audioflinger/AudioFlinger.cpp | 710 | ||||
-rw-r--r-- | libs/audioflinger/AudioFlinger.h | 101 | ||||
-rw-r--r-- | libs/audioflinger/AudioHardwareGeneric.cpp | 46 | ||||
-rw-r--r-- | libs/audioflinger/AudioHardwareGeneric.h | 30 | ||||
-rw-r--r-- | libs/audioflinger/AudioHardwareInterface.cpp | 59 | ||||
-rw-r--r-- | libs/audioflinger/AudioHardwareStub.cpp | 36 | ||||
-rw-r--r-- | libs/audioflinger/AudioHardwareStub.h | 28 | ||||
-rw-r--r-- | libs/audioflinger/AudioMixer.cpp | 278 | ||||
-rw-r--r-- | libs/audioflinger/AudioMixer.h | 18 | ||||
-rw-r--r-- | libs/audioflinger/AudioResampler.cpp | 350 | ||||
-rw-r--r-- | libs/audioflinger/AudioResamplerCubic.cpp | 18 | ||||
-rw-r--r-- | libs/audioflinger/AudioResamplerSinc.cpp | 292 | ||||
-rw-r--r-- | libs/audioflinger/AudioResamplerSinc.h | 23 |
18 files changed, 1678 insertions, 713 deletions
diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/libs/audioflinger/A2dpAudioInterface.cpp new file mode 100644 index 0000000..d54795c --- /dev/null +++ b/libs/audioflinger/A2dpAudioInterface.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2008 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 <math.h> + +#define LOG_NDEBUG 0 +#define LOG_TAG "A2dpAudioInterface" +#include <utils/Log.h> +#include <utils/String8.h> + +#include "A2dpAudioInterface.h" +#include "audio/liba2dp.h" + + +namespace android { + +// ---------------------------------------------------------------------------- + +A2dpAudioInterface::A2dpAudioInterface() : + mOutput(0) +{ +} + +A2dpAudioInterface::~A2dpAudioInterface() +{ + delete mOutput; +} + +status_t A2dpAudioInterface::initCheck() +{ + return 0; +} + +AudioStreamOut* A2dpAudioInterface::openOutputStream( + int format, int channelCount, uint32_t sampleRate, status_t *status) +{ + LOGD("A2dpAudioInterface::openOutputStream %d, %d, %d\n", format, channelCount, sampleRate); + Mutex::Autolock lock(mLock); + status_t err = 0; + + // only one output stream allowed + if (mOutput) { + if (status) + *status = -1; + return NULL; + } + + // create new output stream + A2dpAudioStreamOut* out = new A2dpAudioStreamOut(); + if ((err = out->set(format, channelCount, sampleRate)) == NO_ERROR) { + mOutput = out; + } else { + delete out; + } + + if (status) + *status = err; + return mOutput; +} + +AudioStreamIn* A2dpAudioInterface::openInputStream( + int format, int channelCount, uint32_t sampleRate, status_t *status) +{ + if (status) + *status = -1; + return NULL; +} + +status_t A2dpAudioInterface::standby() +{ + return 0; +} + +status_t A2dpAudioInterface::setMicMute(bool state) +{ + return 0; +} + +status_t A2dpAudioInterface::getMicMute(bool* state) +{ + return 0; +} + +status_t A2dpAudioInterface::setParameter(const char *key, const char *value) +{ + LOGD("setParameter %s,%s\n", key, value); + return 0; +} + +status_t A2dpAudioInterface::setVoiceVolume(float v) +{ + return 0; +} + +status_t A2dpAudioInterface::setMasterVolume(float v) +{ + return 0; +} + +status_t A2dpAudioInterface::doRouting() +{ + return 0; +} + +status_t A2dpAudioInterface::dump(int fd, const Vector<String16>& args) +{ + return 0; +} + +// ---------------------------------------------------------------------------- + +A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() : + mFd(-1), mStartCount(0), mRetryCount(0), mData(NULL), + mInitialized(false), mBufferRemaining(0) +{ +} + +status_t A2dpAudioInterface::A2dpAudioStreamOut::set( + int format, int channels, uint32_t rate) +{ + LOGD("A2dpAudioStreamOut::set %d, %d, %d\n", format, channels, rate); + + // fix up defaults + if (format == 0) format = AudioSystem::PCM_16_BIT; + if (channels == 0) channels = channelCount(); + if (rate == 0) rate = sampleRate(); + + // check values + if ((format != AudioSystem::PCM_16_BIT) || + (channels != channelCount()) || + (rate != sampleRate())) + return BAD_VALUE; + + return NO_ERROR; +} + +A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut() +{ + if (mData) + a2dp_cleanup(mData); +} + +ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes) +{ + if (!mInitialized) { + int ret = a2dp_init("00:00:00:00:00:00", 44100, 2, &mData); + if (ret) + return ret; + mInitialized = true; + } + + size_t remaining = bytes; + while (remaining > 0) { + int written = a2dp_write(mData, buffer, remaining); + remaining -= written; + buffer = ((char *)buffer) + written; + } + + return bytes; +} + +status_t A2dpAudioInterface::A2dpAudioStreamOut::standby() +{ + return 0; +} + +status_t A2dpAudioInterface::A2dpAudioStreamOut::dump(int fd, const Vector<String16>& args) +{ + return NO_ERROR; +} + + +}; // namespace android diff --git a/libs/audioflinger/A2dpAudioInterface.h b/libs/audioflinger/A2dpAudioInterface.h new file mode 100644 index 0000000..03bf933 --- /dev/null +++ b/libs/audioflinger/A2dpAudioInterface.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2008 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 A2DP_AUDIO_HARDWARE_H +#define A2DP_AUDIO_HARDWARE_H + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/threads.h> + +#include <hardware/AudioHardwareBase.h> + + +namespace android { + +class A2dpAudioInterface : public AudioHardwareBase +{ + class A2dpAudioStreamOut; + +public: + A2dpAudioInterface(); + virtual ~A2dpAudioInterface(); + virtual status_t initCheck(); + virtual status_t standby(); + + virtual status_t setVoiceVolume(float volume); + virtual status_t setMasterVolume(float volume); + + // mic mute + virtual status_t setMicMute(bool state); + virtual status_t getMicMute(bool* state); + + // Temporary interface, do not use + // TODO: Replace with a more generic key:value get/set mechanism + virtual status_t setParameter(const char *key, const char *value); + + // create I/O streams + virtual AudioStreamOut* openOutputStream( + int format=0, + int channelCount=0, + uint32_t sampleRate=0, + status_t *status=0); + + virtual AudioStreamIn* openInputStream( + int format, + int channelCount, + uint32_t sampleRate, + status_t *status); + +protected: + virtual status_t doRouting(); + virtual status_t dump(int fd, const Vector<String16>& args); + +private: + class A2dpAudioStreamOut : public AudioStreamOut { + public: + A2dpAudioStreamOut(); + virtual ~A2dpAudioStreamOut(); + status_t set(int format, + int channelCount, + uint32_t sampleRate); + virtual uint32_t sampleRate() const { return 44100; } + // must be 32-bit aligned - driver only seems to like 4800 + virtual size_t bufferSize() const { return 5120; } + virtual int channelCount() const { return 2; } + virtual int format() const { return AudioSystem::PCM_16_BIT; } + virtual uint32_t latency() const { return 0; } + virtual status_t setVolume(float volume) { return INVALID_OPERATION; } + virtual ssize_t write(const void* buffer, size_t bytes); + status_t standby(); + virtual status_t dump(int fd, const Vector<String16>& args); + + private: + int mFd; + int mStartCount; + int mRetryCount; + void* mData; + bool mInitialized; + +#define kBufferSize 50000 + char mBuffer[kBufferSize]; + int mBufferRemaining; + }; + + Mutex mLock; + A2dpAudioStreamOut* mOutput; +}; + +// ---------------------------------------------------------------------------- + +}; // namespace android + +#endif // A2DP_AUDIO_HARDWARE_H diff --git a/libs/audioflinger/Android.mk b/libs/audioflinger/Android.mk index a9cb303..d16e3e1 100644 --- a/libs/audioflinger/Android.mk +++ b/libs/audioflinger/Android.mk @@ -45,9 +45,12 @@ endif LOCAL_MODULE:= libaudioflinger -ifeq ($(TARGET_ARCH),arm) # not simulator - LOCAL_CFLAGS += -DWITH_BLUETOOTH +ifeq ($(BOARD_HAVE_BLUETOOTH),true) + LOCAL_SRC_FILES += A2dpAudioInterface.cpp + LOCAL_SHARED_LIBRARIES += liba2dp + LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP LOCAL_C_INCLUDES += $(call include-path-for, bluez-libs) + LOCAL_C_INCLUDES += $(call include-path-for, bluez-utils) endif include $(BUILD_SHARED_LIBRARY) diff --git a/libs/audioflinger/AudioDumpInterface.cpp b/libs/audioflinger/AudioDumpInterface.cpp index 5ff2f18..8eee9cc 100644 --- a/libs/audioflinger/AudioDumpInterface.cpp +++ b/libs/audioflinger/AudioDumpInterface.cpp @@ -2,16 +2,16 @@ ** ** Copyright 2008, 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 +** 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 +** 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 +** 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. */ @@ -28,6 +28,8 @@ namespace android { +bool gFirst = true; // true if first write after a standby + // ---------------------------------------------------------------------------- AudioDumpInterface::AudioDumpInterface(AudioHardwareInterface* hw) @@ -40,17 +42,25 @@ AudioDumpInterface::AudioDumpInterface(AudioHardwareInterface* hw) } +AudioDumpInterface::~AudioDumpInterface() +{ + if(mFinalInterface) delete mFinalInterface; + if(mStreamOut) delete mStreamOut; +} + + status_t AudioDumpInterface::standby() { if(mStreamOut) mStreamOut->Close(); + gFirst = true; return mFinalInterface->standby(); } AudioStreamOut* AudioDumpInterface::openOutputStream( - int format, int channelCount, uint32_t sampleRate) + int format, int channelCount, uint32_t sampleRate, status_t *status) { - AudioStreamOut* outFinal = mFinalInterface->openOutputStream(format, channelCount, sampleRate); + AudioStreamOut* outFinal = mFinalInterface->openOutputStream(format, channelCount, sampleRate, status); if(outFinal) { mStreamOut = new AudioStreamOutDump(outFinal); @@ -69,13 +79,26 @@ AudioStreamOutDump::AudioStreamOutDump( AudioStreamOut* finalStream) mOutFile = 0; } + +AudioStreamOutDump::~AudioStreamOutDump() +{ + Close(); + delete mFinalStream; +} + ssize_t AudioStreamOutDump::write(const void* buffer, size_t bytes) { ssize_t ret; - + ret = mFinalStream->write(buffer, bytes); - if(!mOutFile) { - mOutFile = fopen(FLINGER_DUMP_NAME, "ab"); + if(!mOutFile && gFirst) { + gFirst = false; + // check if dump file exist + mOutFile = fopen(FLINGER_DUMP_NAME, "r"); + if(mOutFile) { + fclose(mOutFile); + mOutFile = fopen(FLINGER_DUMP_NAME, "ab"); + } } if (mOutFile) { fwrite(buffer, bytes, 1, mOutFile); diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h index 732b97d..a65e56a 100644 --- a/libs/audioflinger/AudioDumpInterface.h +++ b/libs/audioflinger/AudioDumpInterface.h @@ -2,16 +2,16 @@ ** ** Copyright 2008, 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 +** 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 +** 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 +** 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. */ @@ -21,33 +21,35 @@ #include <stdint.h> #include <sys/types.h> -#include <hardware/AudioHardwareInterface.h> +#include <hardware/AudioHardwareBase.h> namespace android { -#define FLINGER_DUMP_NAME "/tmp/FlingerOut.pcm" // name of file used for dump +#define FLINGER_DUMP_NAME "/data/FlingerOut.pcm" // name of file used for dump class AudioStreamOutDump : public AudioStreamOut { public: AudioStreamOutDump( AudioStreamOut* FinalStream); + ~AudioStreamOutDump(); virtual ssize_t write(const void* buffer, size_t bytes); - + virtual uint32_t sampleRate() const { return mFinalStream->sampleRate(); } virtual size_t bufferSize() const { return mFinalStream->bufferSize(); } virtual int channelCount() const { return mFinalStream->channelCount(); } virtual int format() const { return mFinalStream->format(); } + virtual uint32_t latency() const { return mFinalStream->latency(); } virtual status_t setVolume(float volume) { return mFinalStream->setVolume(volume); } virtual status_t dump(int fd, const Vector<String16>& args) { return mFinalStream->dump(fd, args); } void Close(void); private: - AudioStreamOut *mFinalStream; - FILE *mOutFile; // output file + AudioStreamOut *mFinalStream; + FILE *mOutFile; // output file }; -class AudioDumpInterface : public AudioHardwareInterface +class AudioDumpInterface : public AudioHardwareBase { public: @@ -56,10 +58,10 @@ public: virtual AudioStreamOut* openOutputStream( int format=0, int channelCount=0, - uint32_t sampleRate=0); + uint32_t sampleRate=0, + status_t *status=0); + virtual ~AudioDumpInterface(); - virtual ~AudioDumpInterface() - {delete mFinalInterface;} virtual status_t initCheck() {return mFinalInterface->initCheck();} virtual status_t setVoiceVolume(float volume) @@ -67,13 +69,6 @@ public: virtual status_t setMasterVolume(float volume) {return mFinalInterface->setMasterVolume(volume);} - virtual status_t setRouting(int mode, uint32_t routes) - {return mFinalInterface->setRouting(mode, routes);} - virtual status_t getRouting(int mode, uint32_t* routes) - {return mFinalInterface->getRouting(mode, routes);} - virtual status_t getMode(int* mode) - {return mFinalInterface->getMode(mode);} - // mic mute virtual status_t setMicMute(bool state) {return mFinalInterface->setMicMute(state);} @@ -83,17 +78,17 @@ public: virtual status_t setParameter(const char* key, const char* value) {return mFinalInterface->setParameter(key, value);} - virtual AudioStreamIn* openInputStream( int format, int channelCount, uint32_t sampleRate) - {return mFinalInterface->openInputStream( format, channelCount, sampleRate);} + virtual AudioStreamIn* openInputStream( int format, int channelCount, uint32_t sampleRate, status_t *status) + {return mFinalInterface->openInputStream( format, channelCount, sampleRate, status);} virtual status_t dump(int fd, const Vector<String16>& args) { return mFinalInterface->dumpState(fd, args); } protected: - virtual status_t doRouting() {return 0;} - + virtual status_t doRouting() {return mFinalInterface->setRouting(mMode, mRoutes[mMode]);} + AudioHardwareInterface *mFinalInterface; AudioStreamOutDump *mStreamOut; - + }; }; // namespace android diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp index fb21629..53b18ad 100644 --- a/libs/audioflinger/AudioFlinger.cpp +++ b/libs/audioflinger/AudioFlinger.cpp @@ -31,6 +31,8 @@ #include <utils/String16.h> #include <utils/threads.h> +#include <cutils/properties.h> + #include <media/AudioTrack.h> #include <media/AudioRecord.h> @@ -41,9 +43,13 @@ #include "AudioMixer.h" #include "AudioFlinger.h" +#ifdef WITH_A2DP +#include "A2dpAudioInterface.h" +#endif + namespace android { -static const nsecs_t kStandbyTimeInNsecs = seconds(3); +//static const nsecs_t kStandbyTimeInNsecs = seconds(3); static const unsigned long kBufferRecoveryInUsecs = 2000; static const unsigned long kMaxBufferRecoveryInUsecs = 20000; static const float MAX_GAIN = 4096.0f; @@ -93,8 +99,9 @@ static bool settingsAllowed() { AudioFlinger::AudioFlinger() : BnAudioFlinger(), Thread(false), - mMasterVolume(0), mMasterMute(true), - mAudioMixer(0), mAudioHardware(0), mOutput(0), mAudioRecordThread(0), + mMasterVolume(0), mMasterMute(true), mHardwareAudioMixer(0), mA2dpAudioMixer(0), + mAudioMixer(0), mAudioHardware(0), mA2dpAudioInterface(0), + mHardwareOutput(0), mA2dpOutput(0), mOutput(0), mAudioRecordThread(0), mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0), mMixBuffer(0), mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mStandby(false), mInWrite(false) @@ -105,17 +112,14 @@ AudioFlinger::AudioFlinger() if (mAudioHardware->initCheck() == NO_ERROR) { // open 16-bit output stream for s/w mixer mHardwareStatus = AUDIO_HW_OUTPUT_OPEN; - mOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT); + status_t status; + mHardwareOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status); mHardwareStatus = AUDIO_HW_IDLE; - if (mOutput) { - mSampleRate = mOutput->sampleRate(); - mChannelCount = mOutput->channelCount(); - mFormat = mOutput->format(); - mMixBufferSize = mOutput->bufferSize(); - mFrameCount = mMixBufferSize / mChannelCount / sizeof(int16_t); - mMixBuffer = new int16_t[mFrameCount * mChannelCount]; - memset(mMixBuffer, 0, mMixBufferSize); - mAudioMixer = new AudioMixer(mFrameCount, mSampleRate); + if (mHardwareOutput) { + mSampleRate = mHardwareOutput->sampleRate(); + mHardwareAudioMixer = new AudioMixer(getOutputFrameCount(mHardwareOutput), mSampleRate); + setOutput(mHardwareOutput); + // FIXME - this should come from settings setMasterVolume(1.0f); setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL); @@ -124,20 +128,87 @@ AudioFlinger::AudioFlinger() setMode(AudioSystem::MODE_NORMAL); mMasterMute = false; } else { - LOGE("Failed to initialize output stream"); + LOGE("Failed to initialize output stream, status: %d", status); } - } else { + +#ifdef WITH_A2DP + // Create A2DP interface + mA2dpAudioInterface = new A2dpAudioInterface(); + mA2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status); + mA2dpAudioMixer = new AudioMixer(getOutputFrameCount(mA2dpOutput), mA2dpOutput->sampleRate()); + + // create a buffer big enough for both hardware and A2DP audio output. + size_t hwFrameCount = getOutputFrameCount(mHardwareOutput); + size_t a2dpFrameCount = getOutputFrameCount(mA2dpOutput); + size_t frameCount = (hwFrameCount > a2dpFrameCount ? hwFrameCount : a2dpFrameCount); +#else + size_t frameCount = getOutputFrameCount(mHardwareOutput); +#endif + // FIXME - Current mixer implementation only supports stereo output: Always + // Allocate a stereo buffer even if HW output is mono. + mMixBuffer = new int16_t[frameCount * 2]; + memset(mMixBuffer, 0, frameCount * 2 * sizeof(int16_t)); + + // Start record thread + mAudioRecordThread = new AudioRecordThread(mAudioHardware); + if (mAudioRecordThread != 0) { + mAudioRecordThread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO); + } + } else { LOGE("Couldn't even initialize the stubbed audio hardware!"); } + + char value[PROPERTY_VALUE_MAX]; + // FIXME: What property should this be??? + property_get("ro.audio.silent", value, "0"); + if (atoi(value)) { + LOGD("Silence is golden"); + mMasterMute = true; + } } AudioFlinger::~AudioFlinger() { + if (mAudioRecordThread != 0) { + mAudioRecordThread->exit(); + mAudioRecordThread.clear(); + } delete mOutput; + delete mA2dpOutput; delete mAudioHardware; + delete mA2dpAudioInterface; delete [] mMixBuffer; - delete mAudioMixer; - mAudioRecordThread.clear(); + delete mHardwareAudioMixer; + delete mA2dpAudioMixer; +} + +void AudioFlinger::setOutput(AudioStreamOut* output) +{ + // lock on mOutputLock to prevent threadLoop() from starving us + Mutex::Autolock _l2(mOutputLock); + + // to synchronize with threadLoop() + Mutex::Autolock _l(mLock); + + if (mOutput != output) { + mSampleRate = output->sampleRate(); + mChannelCount = output->channelCount(); + + // FIXME - Current mixer implementation only supports stereo output + if (mChannelCount == 1) { + LOGE("Invalid audio hardware channel count"); + } + mFormat = output->format(); + mFrameCount = getOutputFrameCount(output); + + mAudioMixer = (output == mA2dpOutput ? mA2dpAudioMixer : mHardwareAudioMixer); + mOutput = output; + } +} + +size_t AudioFlinger::getOutputFrameCount(AudioStreamOut* output) +{ + return output->bufferSize() / output->channelCount() / sizeof(int16_t); } status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args) @@ -201,8 +272,8 @@ status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args) const size_t SIZE = 256; char buffer[SIZE]; String8 result; - - snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", audioMixer().trackNames()); + + snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", audioMixer()->trackNames()); result.append(buffer); snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime)); result.append(buffer); @@ -254,17 +325,26 @@ status_t AudioFlinger::dump(int fd, const Vector<String16>& args) // Thread virtuals bool AudioFlinger::threadLoop() { - nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2; unsigned long sleepTime = kBufferRecoveryInUsecs; - const size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t); int16_t* curBuf = mMixBuffer; Vector< sp<Track> > tracksToRemove; - size_t enabledTracks; + size_t enabledTracks = 0; nsecs_t standbyTime = systemTime(); + AudioMixer* mixer = 0; + size_t frameCount = 0; + int channelCount = 0; + uint32_t sampleRate = 0; + AudioStreamOut* output = 0; do { enabledTracks = 0; - { // scope for the lock + { // scope for the mLock + + // locking briefly on the secondary mOutputLock is necessary to avoid + // having this thread starve the thread that called setOutput() + mOutputLock.lock(); + mOutputLock.unlock(); + Mutex::Autolock _l(mLock); const SortedVector< wp<Track> >& activeTracks = mActiveTracks; @@ -286,6 +366,15 @@ bool AudioFlinger::threadLoop() continue; } + // get active mixer and output parameter while the lock is held and keep them + // consistent till the next loop. + + mixer = audioMixer(); + frameCount = mFrameCount; + channelCount = mChannelCount; + sampleRate = mSampleRate; + output = mOutput; + // find out which tracks need to be processed size_t count = activeTracks.size(); for (size_t i=0 ; i<count ; i++) { @@ -294,13 +383,11 @@ bool AudioFlinger::threadLoop() Track* const track = t.get(); audio_track_cblk_t* cblk = track->cblk(); - uint32_t u = cblk->user; - uint32_t s = cblk->server; // The first time a track is added we wait // for all its buffers to be filled before processing it - audioMixer().setActiveTrack(track->name()); - if ((u > s) && (track->isReady(u, s) || track->isStopped()) && + mixer->setActiveTrack(track->name()); + if (cblk->framesReady() && (track->isReady() || track->isStopped()) && !track->isPaused()) { //LOGD("u=%08x, s=%08x [OK]", u, s); @@ -325,9 +412,8 @@ bool AudioFlinger::threadLoop() } // XXX: these things DON'T need to be done each time - AudioMixer& mixer(audioMixer()); - mixer.setBufferProvider(track); - mixer.enable(AudioMixer::MIXING); + mixer->setBufferProvider(track); + mixer->enable(AudioMixer::MIXING); int param; if ( track->mFillingUpStatus == Track::FS_FILLED) { @@ -342,15 +428,15 @@ bool AudioFlinger::threadLoop() } else { param = AudioMixer::RAMP_VOLUME; } - mixer.setParameter(param, AudioMixer::VOLUME0, left); - mixer.setParameter(param, AudioMixer::VOLUME1, right); - mixer.setParameter( + mixer->setParameter(param, AudioMixer::VOLUME0, left); + mixer->setParameter(param, AudioMixer::VOLUME1, right); + mixer->setParameter( AudioMixer::TRACK, AudioMixer::FORMAT, track->format()); - mixer.setParameter( + mixer->setParameter( AudioMixer::TRACK, AudioMixer::CHANNEL_COUNT, track->channelCount()); - mixer.setParameter( + mixer->setParameter( AudioMixer::RESAMPLE, AudioMixer::SAMPLE_RATE, int(cblk->sampleRate)); @@ -361,8 +447,7 @@ bool AudioFlinger::threadLoop() } else { //LOGD("u=%08x, s=%08x [NOT READY]", u, s); if (track->isStopped()) { - track->mFillingUpStatus = Track::FS_FILLING; - track->mFlags = 0; + track->reset(); } if (track->isTerminated() || track->isStopped() || track->isPaused()) { // We have consumed all the buffers of this track. @@ -378,7 +463,7 @@ bool AudioFlinger::threadLoop() } } // LOGV("disable(%d)", track->name()); - audioMixer().disable(AudioMixer::MIXING); + mixer->disable(AudioMixer::MIXING); } } @@ -390,26 +475,27 @@ bool AudioFlinger::threadLoop() mActiveTracks.remove(track); if (track->isTerminated()) { mTracks.remove(track); - audioMixer().deleteTrackName(track->mName); + mixer->deleteTrackName(track->mName); } } - } - } - + } + } if (LIKELY(enabledTracks)) { // mix buffers... - audioMixer().process(curBuf); + mixer->process(curBuf); // output audio to hardware mLastWriteTime = systemTime(); mInWrite = true; - mOutput->write(curBuf, mixBufferSize); + size_t mixBufferSize = frameCount*channelCount*sizeof(int16_t); + output->write(curBuf, mixBufferSize); mNumWrites++; mInWrite = false; mStandby = false; nsecs_t temp = systemTime(); standbyTime = temp + kStandbyTimeInNsecs; nsecs_t delta = temp - mLastWriteTime; + nsecs_t maxPeriod = seconds(frameCount) / sampleRate * 2; if (delta > maxPeriod) { LOGW("write blocked for %llu msecs", ns2ms(delta)); mNumDelayedWrites++; @@ -458,43 +544,60 @@ sp<IAudioTrack> AudioFlinger::createTrack( uint32_t sampleRate, int format, int channelCount, - int bufferCount, - uint32_t flags) + int frameCount, + uint32_t flags, + const sp<IMemory>& sharedBuffer, + status_t *status) { + sp<Track> track; + sp<TrackHandle> trackHandle; + sp<Client> client; + wp<Client> wclient; + status_t lStatus; + if (streamType >= AudioTrack::NUM_STREAM_TYPES) { LOGE("invalid stream type"); - return NULL; + lStatus = BAD_VALUE; + goto Exit; } - if (sampleRate > MAX_SAMPLE_RATE) { + // Resampler implementation limits input sampling rate to 2 x output sampling rate. + if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) { LOGE("Sample rate out of range: %d", sampleRate); - return NULL; + lStatus = BAD_VALUE; + goto Exit; } - sp<Track> track; - sp<TrackHandle> trackHandle; - Mutex::Autolock _l(mLock); + { + Mutex::Autolock _l(mLock); - if (mSampleRate == 0) { - LOGE("Audio driver not initialized."); - return trackHandle; - } + if (mSampleRate == 0) { + LOGE("Audio driver not initialized."); + lStatus = NO_INIT; + goto Exit; + } - sp<Client> client; - wp<Client> wclient = mClients.valueFor(pid); + wclient = mClients.valueFor(pid); - if (wclient != NULL) { - client = wclient.promote(); - } else { - client = new Client(this, pid); - mClients.add(pid, client); + if (wclient != NULL) { + client = wclient.promote(); + } else { + client = new Client(this, pid); + mClients.add(pid, client); + } + + track = new Track(this, client, streamType, sampleRate, format, + channelCount, frameCount, sharedBuffer); + mTracks.add(track); + trackHandle = new TrackHandle(track); + + lStatus = NO_ERROR; } - // FIXME: Buffer size should be based on sample rate for consistent latency - track = new Track(this, client, streamType, sampleRate, format, - channelCount, bufferCount, channelCount == 1 ? mMixBufferSize>>1 : mMixBufferSize); - mTracks.add(track); - trackHandle = new TrackHandle(track); +Exit: + if(status) { + *status = lStatus; + } return trackHandle; } @@ -518,6 +621,16 @@ size_t AudioFlinger::frameCount() const return mFrameCount; } +uint32_t AudioFlinger::latency() const +{ + if (mOutput) { + return mOutput->latency(); + } + else { + return 0; + } +} + status_t AudioFlinger::setMasterVolume(float value) { // check calling permissions @@ -549,6 +662,21 @@ status_t AudioFlinger::setRouting(int mode, uint32_t routes, uint32_t mask) return BAD_VALUE; } +#ifdef WITH_A2DP + LOGD("setRouting %d %d %d\n", mode, routes, mask); + if (mode == AudioSystem::MODE_NORMAL && + (mask & AudioSystem::ROUTE_BLUETOOTH_A2DP)) { + if (routes & AudioSystem::ROUTE_BLUETOOTH_A2DP) { + LOGD("set output to A2DP\n"); + setOutput(mA2dpOutput); + } else { + LOGD("set output to hardware audio\n"); + setOutput(mHardwareOutput); + } + LOGD("setOutput done\n"); + } +#endif + AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_HW_GET_ROUTING; uint32_t r; @@ -656,7 +784,7 @@ status_t AudioFlinger::setStreamVolume(int stream, float value) if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) { return BAD_VALUE; } - + mStreamTypes[stream].volume = value; status_t ret = NO_ERROR; if (stream == AudioTrack::VOICE_CALL) { @@ -750,6 +878,7 @@ status_t AudioFlinger::addTrack(const sp<Track>& track) // buffers before playing. This is to ensure the client will // effectively get the latency it requested. track->mFillingUpStatus = Track::FS_FILLING; + track->mResetDone = false; mActiveTracks.add(track); return NO_ERROR; } @@ -771,7 +900,7 @@ void AudioFlinger::remove_track_l(wp<Track> track, int name) if (t!=NULL) { t->reset(); } - audioMixer().deleteTrackName(name); + audioMixer()->deleteTrackName(name); mActiveTracks.remove(track); mWaitWorkCV.broadcast(); } @@ -789,7 +918,7 @@ void AudioFlinger::destroyTrack(const sp<Track>& track) if (mActiveTracks.indexOf(track) < 0) { LOGV("remove track (%d) and delete from mixer", track->name()); mTracks.remove(track); - audioMixer().deleteTrackName(keep->name()); + audioMixer()->deleteTrackName(keep->name()); } } @@ -823,38 +952,53 @@ AudioFlinger::TrackBase::TrackBase( uint32_t sampleRate, int format, int channelCount, - int bufferCount, - int bufferSize) + int frameCount, + const sp<IMemory>& sharedBuffer) : RefBase(), mAudioFlinger(audioFlinger), mClient(client), mStreamType(streamType), - mFormat(format), - mChannelCount(channelCount), - mBufferCount(bufferCount), - mFlags(0), - mBufferSize(bufferSize), + mFrameCount(0), mState(IDLE), - mClientTid(-1) + mClientTid(-1), + mFormat(format), + mFlags(0) { - mName = audioFlinger->audioMixer().getTrackName(); + mName = audioFlinger->audioMixer()->getTrackName(); if (mName < 0) { LOGE("no more track names availlable"); return; } + LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size()); + + // LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize); - size_t size = sizeof(audio_track_cblk_t) + bufferCount * bufferSize; + size_t size = sizeof(audio_track_cblk_t); + size_t bufferSize = frameCount*channelCount*sizeof(int16_t); + if (sharedBuffer == 0) { + size += bufferSize; + } + mCblkMemory = client->heap()->allocate(size); if (mCblkMemory != 0) { mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer()); if (mCblk) { // construct the shared structure in-place. new(mCblk) audio_track_cblk_t(); // clear all buffers - mCblk->size = bufferSize; + mCblk->frameCount = frameCount; mCblk->sampleRate = sampleRate; - mBuffers = (char*)mCblk + sizeof(audio_track_cblk_t); - memset(mBuffers, 0, bufferCount * bufferSize); + mCblk->channels = channelCount; + if (sharedBuffer == 0) { + mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t); + memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t)); + // Force underrun condition to avoid false underrun callback until first data is + // written to buffer + mCblk->flowControlFlag = 1; + } else { + mBuffer = sharedBuffer->pointer(); + } + mBufferEnd = (uint8_t *)mBuffer + bufferSize; } } else { LOGE("not enough memory for AudioTrack size=%u", size); @@ -873,15 +1017,16 @@ AudioFlinger::TrackBase::~TrackBase() void AudioFlinger::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer) { buffer->raw = 0; - buffer->frameCount = 0; + mFrameCount = buffer->frameCount; step(); + buffer->frameCount = 0; } bool AudioFlinger::TrackBase::step() { bool result; audio_track_cblk_t* cblk = this->cblk(); - - result = cblk->stepServer(bufferCount()); + + result = cblk->stepServer(mFrameCount); if (!result) { LOGV("stepServer failed acquiring cblk mutex"); mFlags |= STEPSERVER_FAILED; @@ -894,7 +1039,10 @@ void AudioFlinger::TrackBase::reset() { cblk->user = 0; cblk->server = 0; - mFlags = 0; + cblk->userBase = 0; + cblk->serverBase = 0; + mFlags = 0; + LOGV("TrackBase::reset"); } sp<IMemory> AudioFlinger::TrackBase::getCblk() const @@ -906,6 +1054,27 @@ int AudioFlinger::TrackBase::sampleRate() const { return mCblk->sampleRate; } +int AudioFlinger::TrackBase::channelCount() const { + return mCblk->channels; +} + +void* AudioFlinger::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const { + audio_track_cblk_t* cblk = this->cblk(); + int16_t *bufferStart = (int16_t *)mBuffer + (offset-cblk->serverBase)*cblk->channels; + int16_t *bufferEnd = bufferStart + frames * cblk->channels; + + // Check validity of returned pointer in case the track control block would have been corrupted. + if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd) { + LOGW("TrackBase::getBuffer buffer out of range:\n start: %p, end %p , mBuffer %p mBufferEnd %p\n \ + server %d, serverBase %d, user %d, userBase %d", + bufferStart, bufferEnd, mBuffer, mBufferEnd, + cblk->server, cblk->serverBase, cblk->user, cblk->userBase); + return 0; + } + + return bufferStart; +} + // ---------------------------------------------------------------------------- AudioFlinger::Track::Track( @@ -915,13 +1084,14 @@ AudioFlinger::Track::Track( uint32_t sampleRate, int format, int channelCount, - int bufferCount, - int bufferSize) - : TrackBase(audioFlinger, client, streamType, sampleRate, format, channelCount, bufferCount, bufferSize) + int frameCount, + const sp<IMemory>& sharedBuffer) + : TrackBase(audioFlinger, client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer) { mVolume[0] = 1.0f; mVolume[1] = 1.0f; mMute = false; + mSharedBuffer = sharedBuffer; } AudioFlinger::Track::~Track() @@ -943,8 +1113,8 @@ void AudioFlinger::Track::dump(char* buffer, size_t size) mClient->pid(), mStreamType, mFormat, - mChannelCount, - mBufferCount, + mCblk->channels, + mFrameCount, mState, mMute, mFillingUpStatus, @@ -958,36 +1128,50 @@ void AudioFlinger::Track::dump(char* buffer, size_t size) status_t AudioFlinger::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer) { audio_track_cblk_t* cblk = this->cblk(); - uint32_t u = cblk->user; - uint32_t s = cblk->server; - - // Check if last stepServer failed, try to step now + uint32_t framesReady; + uint32_t framesReq = buffer->frameCount; + + // Check if last stepServer failed, try to step now if (mFlags & TrackBase::STEPSERVER_FAILED) { if (!step()) goto getNextBuffer_exit; LOGV("stepServer recovered"); mFlags &= ~TrackBase::STEPSERVER_FAILED; } - if (LIKELY(u > s)) { - int index = s & audio_track_cblk_t::BUFFER_MASK; - buffer->raw = getBuffer(index); - buffer->frameCount = mAudioFlinger->frameCount(); - return NO_ERROR; + framesReady = cblk->framesReady(); + + if (LIKELY(framesReady)) { + uint32_t s = cblk->server; + uint32_t bufferEnd = cblk->serverBase + cblk->frameCount; + + bufferEnd = (cblk->loopEnd < bufferEnd) ? cblk->loopEnd : bufferEnd; + if (framesReq > framesReady) { + framesReq = framesReady; + } + if (s + framesReq > bufferEnd) { + framesReq = bufferEnd - s; + } + + buffer->raw = getBuffer(s, framesReq); + if (buffer->raw == 0) goto getNextBuffer_exit; + + buffer->frameCount = framesReq; + return NO_ERROR; } + getNextBuffer_exit: buffer->raw = 0; buffer->frameCount = 0; return NOT_ENOUGH_DATA; } -bool AudioFlinger::Track::isReady(uint32_t u, int32_t s) const { +bool AudioFlinger::Track::isReady() const { if (mFillingUpStatus != FS_FILLING) return true; - const uint32_t u_seq = u & audio_track_cblk_t::SEQUENCE_MASK; - const uint32_t u_buf = u & audio_track_cblk_t::BUFFER_MASK; - const uint32_t s_seq = s & audio_track_cblk_t::SEQUENCE_MASK; - const uint32_t s_buf = s & audio_track_cblk_t::BUFFER_MASK; - if (u_seq > s_seq && u_buf == s_buf) { + + if (mCblk->framesReady() >= mCblk->frameCount || + mCblk->forceReady) { mFillingUpStatus = FS_FILLED; + mCblk->forceReady = 0; return true; } return false; @@ -1006,7 +1190,7 @@ void AudioFlinger::Track::stop() Mutex::Autolock _l(mAudioFlinger->mLock); if (mState > STOPPED) { mState = STOPPED; - // If the track is not active (PAUSED and buffers full), flush buffers + // If the track is not active (PAUSED and buffers full), flush buffers if (mAudioFlinger->mActiveTracks.indexOf(this) < 0) { reset(); } @@ -1038,15 +1222,24 @@ void AudioFlinger::Track::flush() // NOTE: reset() will reset cblk->user and cblk->server with // the risk that at the same time, the AudioMixer is trying to read // data. In this case, getNextBuffer() would return a NULL pointer - // as audio buffer => the AudioMixer code MUST always test that pointer - // returned by getNextBuffer() is not NULL! + // as audio buffer => the AudioMixer code MUST always test that pointer + // returned by getNextBuffer() is not NULL! reset(); } void AudioFlinger::Track::reset() { - TrackBase::reset(); - mFillingUpStatus = FS_FILLING; + // Do not reset twice to avoid discarding data written just after a flush and before + // the audioflinger thread detects the track is stopped. + if (!mResetDone) { + TrackBase::reset(); + // Force underrun condition to avoid false underrun callback until first data is + // written to buffer + mCblk->flowControlFlag = 1; + mCblk->forceReady = 0; + mFillingUpStatus = FS_FILLING; + mResetDone = true; + } } void AudioFlinger::Track::mute(bool muted) @@ -1112,26 +1305,15 @@ status_t AudioFlinger::TrackHandle::onTransact( // ---------------------------------------------------------------------------- -sp<AudioFlinger::AudioRecordThread> AudioFlinger::audioRecordThread() -{ - Mutex::Autolock _l(mLock); - return mAudioRecordThread; -} - -void AudioFlinger::endRecord() -{ - Mutex::Autolock _l(mLock); - mAudioRecordThread.clear(); -} - sp<IAudioRecord> AudioFlinger::openRecord( pid_t pid, int streamType, uint32_t sampleRate, int format, int channelCount, - int bufferCount, - uint32_t flags) + int frameCount, + uint32_t flags, + status_t *status) { sp<AudioRecordThread> thread; sp<RecordTrack> recordTrack; @@ -1139,46 +1321,46 @@ sp<IAudioRecord> AudioFlinger::openRecord( sp<Client> client; wp<Client> wclient; AudioStreamIn* input = 0; + int inFrameCount; + size_t inputBufferSize; + status_t lStatus; // check calling permissions if (!recordingAllowed()) { + lStatus = PERMISSION_DENIED; goto Exit; } if (uint32_t(streamType) >= AudioRecord::NUM_STREAM_TYPES) { LOGE("invalid stream type"); + lStatus = BAD_VALUE; goto Exit; } if (sampleRate > MAX_SAMPLE_RATE) { LOGE("Sample rate out of range"); + lStatus = BAD_VALUE; goto Exit; } if (mSampleRate == 0) { LOGE("Audio driver not initialized"); + lStatus = NO_INIT; goto Exit; } - // Create audio thread - take mutex to prevent race condition - { - Mutex::Autolock _l(mLock); - if (mAudioRecordThread != 0) { - LOGE("Record channel already open"); - goto Exit; - } - thread = new AudioRecordThread(this); - mAudioRecordThread = thread; - } - // It's safe to release the mutex here since the client doesn't get a - // handle until we return from this call - - // open driver, initialize h/w - input = mAudioHardware->openInputStream( - AudioSystem::PCM_16_BIT, channelCount, sampleRate); - if (!input) { - LOGE("Error opening input stream"); - mAudioRecordThread.clear(); + if (mAudioRecordThread == 0) { + LOGE("Audio record thread not started"); + lStatus = NO_INIT; + goto Exit; + } + + + // Check that audio input stream accepts requested audio parameters + inputBufferSize = mAudioHardware->getInputBufferSize(sampleRate, format, channelCount); + if (inputBufferSize == 0) { + lStatus = BAD_VALUE; + LOGE("Bad audio input parameters: sampling rate %u, format %d, channels %d", sampleRate, format, channelCount); goto Exit; } @@ -1194,37 +1376,38 @@ sp<IAudioRecord> AudioFlinger::openRecord( } } + // frameCount must be a multiple of input buffer size + inFrameCount = inputBufferSize/channelCount/sizeof(short); + frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount; + // create new record track and pass to record thread recordTrack = new RecordTrack(this, client, streamType, sampleRate, - format, channelCount, bufferCount, input->bufferSize()); - - // spin up record thread - thread->open(recordTrack, input); - thread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO); + format, channelCount, frameCount); // return to handle to client recordHandle = new RecordHandle(recordTrack); + lStatus = NO_ERROR; Exit: + if (status) { + *status = lStatus; + } return recordHandle; } -status_t AudioFlinger::startRecord() { - sp<AudioRecordThread> t = audioRecordThread(); - if (t == 0) return NO_INIT; - return t->start(); +status_t AudioFlinger::startRecord(RecordTrack* recordTrack) { + if (mAudioRecordThread != 0) { + return mAudioRecordThread->start(recordTrack); + } + return NO_INIT; } -void AudioFlinger::stopRecord() { - sp<AudioRecordThread> t = audioRecordThread(); - if (t != 0) t->stop(); +void AudioFlinger::stopRecord(RecordTrack* recordTrack) { + if (mAudioRecordThread != 0) { + mAudioRecordThread->stop(recordTrack); + } } -void AudioFlinger::exitRecord() -{ - sp<AudioRecordThread> t = audioRecordThread(); - if (t != 0) t->exit(); -} // ---------------------------------------------------------------------------- @@ -1235,55 +1418,69 @@ AudioFlinger::RecordTrack::RecordTrack( uint32_t sampleRate, int format, int channelCount, - int bufferCount, - int bufferSize) + int frameCount) : TrackBase(audioFlinger, client, streamType, sampleRate, format, - channelCount, bufferCount, bufferSize), + channelCount, frameCount, 0), mOverflow(false) { } AudioFlinger::RecordTrack::~RecordTrack() { - mAudioFlinger->audioMixer().deleteTrackName(mName); - mAudioFlinger->exitRecord(); + mAudioFlinger->audioMixer()->deleteTrackName(mName); } status_t AudioFlinger::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer) { - audio_track_cblk_t* cblk = this->cblk(); - const uint32_t u_seq = cblk->user & audio_track_cblk_t::SEQUENCE_MASK; - const uint32_t u_buf = cblk->user & audio_track_cblk_t::BUFFER_MASK; - const uint32_t s_seq = cblk->server & audio_track_cblk_t::SEQUENCE_MASK; - const uint32_t s_buf = cblk->server & audio_track_cblk_t::BUFFER_MASK; - - // Check if last stepServer failed, try to step now - if (mFlags & TrackBase::STEPSERVER_FAILED) { - if (!step()) goto getNextBuffer_exit; - LOGV("stepServer recovered"); - mFlags &= ~TrackBase::STEPSERVER_FAILED; - } + audio_track_cblk_t* cblk = this->cblk(); + uint32_t framesAvail; + uint32_t framesReq = buffer->frameCount; + + // Check if last stepServer failed, try to step now + if (mFlags & TrackBase::STEPSERVER_FAILED) { + if (!step()) goto getNextBuffer_exit; + LOGV("stepServer recovered"); + mFlags &= ~TrackBase::STEPSERVER_FAILED; + } - if (LIKELY(s_seq == u_seq || s_buf != u_buf)) { - buffer->raw = getBuffer(s_buf); - buffer->frameCount = mAudioFlinger->frameCount(); - return NO_ERROR; - } + framesAvail = cblk->framesAvailable_l(); -getNextBuffer_exit: - buffer->raw = 0; - buffer->frameCount = 0; - return NOT_ENOUGH_DATA; + if (LIKELY(framesAvail)) { + uint32_t s = cblk->server; + uint32_t bufferEnd = cblk->serverBase + cblk->frameCount; + + if (framesReq > framesAvail) { + framesReq = framesAvail; + } + if (s + framesReq > bufferEnd) { + framesReq = bufferEnd - s; + } + + buffer->raw = getBuffer(s, framesReq); + if (buffer->raw == 0) goto getNextBuffer_exit; + + buffer->frameCount = framesReq; + return NO_ERROR; + } + +getNextBuffer_exit: + buffer->raw = 0; + buffer->frameCount = 0; + return NOT_ENOUGH_DATA; } status_t AudioFlinger::RecordTrack::start() { - return mAudioFlinger->startRecord(); + return mAudioFlinger->startRecord(this); } void AudioFlinger::RecordTrack::stop() { - mAudioFlinger->stopRecord(); + mAudioFlinger->stopRecord(this); + TrackBase::reset(); + // Force overerrun condition to avoid false overrun callback until first data is + // read from buffer + mCblk->flowControlFlag = 1; } // ---------------------------------------------------------------------------- @@ -1294,7 +1491,9 @@ AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::RecordTrack>& re { } -AudioFlinger::RecordHandle::~RecordHandle() {} +AudioFlinger::RecordHandle::~RecordHandle() { + stop(); +} status_t AudioFlinger::RecordHandle::start() { LOGV("RecordHandle::start()"); @@ -1318,10 +1517,8 @@ status_t AudioFlinger::RecordHandle::onTransact( // ---------------------------------------------------------------------------- -AudioFlinger::AudioRecordThread::AudioRecordThread(const sp<AudioFlinger>& audioFlinger) : - mAudioFlinger(audioFlinger), - mRecordTrack(0), - mInput(0), +AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware) : + mAudioHardware(audioHardware), mActive(false) { } @@ -1333,108 +1530,123 @@ AudioFlinger::AudioRecordThread::~AudioRecordThread() bool AudioFlinger::AudioRecordThread::threadLoop() { LOGV("AudioRecordThread: start record loop"); + AudioBufferProvider::Buffer buffer; + int inBufferSize = 0; + int inFrameCount = 0; + AudioStreamIn* input = 0; + mActive = 0; + // start recording while (!exitPending()) { if (!mActive) { mLock.lock(); if (!mActive && !exitPending()) { LOGV("AudioRecordThread: loop stopping"); + if (input) { + delete input; + input = 0; + } + mRecordTrack.clear(); + mWaitWorkCV.wait(mLock); + LOGV("AudioRecordThread: loop starting"); + if (mRecordTrack != 0) { + input = mAudioHardware->openInputStream(mRecordTrack->format(), + mRecordTrack->channelCount(), + mRecordTrack->sampleRate(), + &mStartStatus); + if (input != 0) { + inBufferSize = input->bufferSize(); + inFrameCount = inBufferSize/input->frameSize(); + } + } else { + mStartStatus = NO_INIT; + } + if (mStartStatus !=NO_ERROR) { + LOGW("record start failed, status %d", mStartStatus); + mActive = false; + mRecordTrack.clear(); + } + mWaitWorkCV.signal(); } mLock.unlock(); - } else { - // promote strong ref so track isn't deleted while we access it - sp<RecordTrack> t = mRecordTrack.promote(); + } else if (mRecordTrack != 0){ - // if we lose the weak reference, client is gone. - if (t == 0) { - LOGV("AudioRecordThread: client deleted track"); - break; - } - - if (LIKELY(t->getNextBuffer(&mBuffer) == NO_ERROR)) { - if (mInput->read(mBuffer.raw, t->mBufferSize) < 0) { + buffer.frameCount = inFrameCount; + if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR)) { + LOGV("AudioRecordThread read: %d frames", buffer.frameCount); + if (input->read(buffer.raw, inBufferSize) < 0) { LOGE("Error reading audio input"); sleep(1); } - t->releaseBuffer(&mBuffer); + mRecordTrack->releaseBuffer(&buffer); + mRecordTrack->overflow(); } // client isn't retrieving buffers fast enough else { - if (!t->setOverflow()) + if (!mRecordTrack->setOverflow()) LOGW("AudioRecordThread: buffer overflow"); + // Release the processor for a while before asking for a new buffer. + // This will give the application more chance to read from the buffer and + // clear the overflow. + usleep(5000); } } - }; - - // close hardware - close(); + } - // delete this object - no more data references after this call - mAudioFlinger->endRecord(); - return false; -} -status_t AudioFlinger::AudioRecordThread::open(const sp<RecordTrack>& recordTrack, AudioStreamIn *input) { - LOGV("AudioRecordThread::open"); - // check for record channel already open - AutoMutex lock(&mLock); - if (mRecordTrack != NULL) { - LOGE("Record channel already open"); - return ALREADY_EXISTS; + if (input) { + delete input; } - mRecordTrack = recordTrack; - mInput = input; - return NO_ERROR; + mRecordTrack.clear(); + + return false; } -status_t AudioFlinger::AudioRecordThread::start() +status_t AudioFlinger::AudioRecordThread::start(RecordTrack* recordTrack) { LOGV("AudioRecordThread::start"); AutoMutex lock(&mLock); - if (mActive) return -EBUSY; + mActive = true; + // If starting the active track, just reset mActive in case a stop + // was pending and exit + if (recordTrack == mRecordTrack.get()) return NO_ERROR; + + if (mRecordTrack != 0) return -EBUSY; - sp<RecordTrack> t = mRecordTrack.promote(); - if (t == 0) return UNKNOWN_ERROR; + mRecordTrack = recordTrack; // signal thread to start LOGV("Signal record thread"); - mActive = true; mWaitWorkCV.signal(); - return NO_ERROR; + mWaitWorkCV.wait(mLock); + LOGV("Record started, status %d", mStartStatus); + return mStartStatus; } -void AudioFlinger::AudioRecordThread::stop() { +void AudioFlinger::AudioRecordThread::stop(RecordTrack* recordTrack) { LOGV("AudioRecordThread::stop"); AutoMutex lock(&mLock); - if (mActive) { + if (mActive && (recordTrack == mRecordTrack.get())) { mActive = false; - mWaitWorkCV.signal(); } } void AudioFlinger::AudioRecordThread::exit() { LOGV("AudioRecordThread::exit"); - AutoMutex lock(&mLock); - requestExit(); - mWaitWorkCV.signal(); + { + AutoMutex lock(&mLock); + requestExit(); + mWaitWorkCV.signal(); + } + requestExitAndWait(); } -status_t AudioFlinger::AudioRecordThread::close() -{ - LOGV("AudioRecordThread::close"); - AutoMutex lock(&mLock); - if (!mInput) return NO_INIT; - delete mInput; - mInput = 0; - return NO_ERROR; -} - status_t AudioFlinger::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h index 8c02617..d9f7b49 100644 --- a/libs/audioflinger/AudioFlinger.h +++ b/libs/audioflinger/AudioFlinger.h @@ -43,13 +43,17 @@ class audio_track_cblk_t; class AudioMixer; class AudioBuffer; + // ---------------------------------------------------------------------------- #define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) #define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) + // ---------------------------------------------------------------------------- +static const nsecs_t kStandbyTimeInNsecs = seconds(3); + class AudioFlinger : public BnAudioFlinger, protected Thread { public: @@ -69,13 +73,16 @@ public: uint32_t sampleRate, int format, int channelCount, - int bufferCount, - uint32_t flags); + int frameCount, + uint32_t flags, + const sp<IMemory>& sharedBuffer, + status_t *status); virtual uint32_t sampleRate() const; virtual int channelCount() const; virtual int format() const; virtual size_t frameCount() const; + virtual size_t latency() const; virtual status_t setMasterVolume(float value); virtual status_t setMasterMute(bool muted); @@ -128,8 +135,9 @@ public: uint32_t sampleRate, int format, int channelCount, - int bufferCount, - uint32_t flags); + int frameCount, + uint32_t flags, + status_t *status); virtual status_t onTransact( uint32_t code, @@ -141,12 +149,15 @@ private: AudioFlinger(); virtual ~AudioFlinger(); + void setOutput(AudioStreamOut* output); + size_t getOutputFrameCount(AudioStreamOut* output); + // Internal dump utilites. status_t dumpPermissionDenial(int fd, const Vector<String16>& args); status_t dumpClients(int fd, const Vector<String16>& args); status_t dumpTracks(int fd, const Vector<String16>& args); status_t dumpInternals(int fd, const Vector<String16>& args); - + // --- Client --- class Client : public RefBase { public: @@ -183,17 +194,17 @@ private: }; enum track_flags { - STEPSERVER_FAILED = 0x01 // StepServer could not acquire cblk->lock mutex + STEPSERVER_FAILED = 0x01 // StepServer could not acquire cblk->lock mutex }; - + TrackBase( const sp<AudioFlinger>& audioFlinger, const sp<Client>& client, int streamType, uint32_t sampleRate, int format, int channelCount, - int bufferCount, - int bufferSize); + int frameCount, + const sp<IMemory>& sharedBuffer); ~TrackBase(); virtual status_t start() = 0; @@ -203,6 +214,7 @@ private: protected: friend class AudioFlinger; friend class RecordHandle; + friend class AudioRecordThread; TrackBase(const TrackBase&); TrackBase& operator = (const TrackBase&); @@ -222,19 +234,11 @@ private: return mFormat; } - int channelCount() const { - return mChannelCount; - } - - int bufferCount() const { - return mBufferCount; - } + int channelCount() const ; int sampleRate() const; - void* getBuffer(int n) const { - return (char*)mBuffers + n * mBufferSize; - } + void* getBuffer(uint32_t offset, uint32_t frames) const; int name() const { return mName; @@ -256,16 +260,15 @@ private: sp<IMemory> mCblkMemory; audio_track_cblk_t* mCblk; int mStreamType; - uint8_t mFormat; - uint8_t mChannelCount; - uint8_t mBufferCount; - uint8_t mFlags; - void* mBuffers; - size_t mBufferSize; + void* mBuffer; + void* mBufferEnd; + uint32_t mFrameCount; int mName; // we don't really need a lock for these int mState; int mClientTid; + uint8_t mFormat; + uint8_t mFlags; }; // playback track @@ -277,8 +280,8 @@ private: uint32_t sampleRate, int format, int channelCount, - int bufferCount, - int bufferSize); + int frameCount, + const sp<IMemory>& sharedBuffer); ~Track(); void dump(char* buffer, size_t size); @@ -312,7 +315,7 @@ private: return mState == PAUSED; } - bool isReady(uint32_t u, int32_t s) const; + bool isReady() const; void setPaused() { mState = PAUSED; } void reset(); @@ -324,6 +327,8 @@ private: enum {FS_FILLING, FS_FILLED, FS_ACTIVE}; mutable uint8_t mFillingUpStatus; int8_t mRetryCount; + sp<IMemory> mSharedBuffer; + bool mResetDone; }; // end of Track friend class AudioBuffer; @@ -366,8 +371,8 @@ private: void remove_track_l(wp<Track> track, int name); void destroyTrack(const sp<Track>& track); - AudioMixer& audioMixer() { - return *mAudioMixer; + AudioMixer* audioMixer() { + return mAudioMixer; } // record track @@ -379,8 +384,7 @@ private: uint32_t sampleRate, int format, int channelCount, - int bufferCount, - int bufferSize); + int frameCount); ~RecordTrack(); virtual status_t start(); @@ -419,43 +423,34 @@ private: class AudioRecordThread : public Thread { public: - AudioRecordThread(const sp<AudioFlinger>& audioFlinger); + AudioRecordThread(AudioHardwareInterface* audioHardware); virtual ~AudioRecordThread(); virtual bool threadLoop(); virtual status_t readyToRun() { return NO_ERROR; } virtual void onFirstRef() {} - status_t open(const sp<RecordTrack>& recordTrack, AudioStreamIn *input); - status_t start(); - void stop(); - status_t close(); + status_t start(RecordTrack* recordTrack); + void stop(RecordTrack* recordTrack); void exit(); - - bool isOpen() { return bool(mRecordTrack != NULL); } private: AudioRecordThread(); - sp<AudioFlinger> mAudioFlinger; - wp<RecordTrack> mRecordTrack; - AudioStreamIn* mInput; + AudioHardwareInterface *mAudioHardware; + sp<RecordTrack> mRecordTrack; Mutex mLock; Condition mWaitWorkCV; - AudioBufferProvider::Buffer mBuffer; volatile bool mActive; + status_t mStartStatus; }; friend class AudioRecordThread; - sp<AudioRecordThread> audioRecordThread(); - void endRecord(); - status_t startRecord(); - void stopRecord(); - void exitRecord(); - - AudioHardwareInterface* audioHardware() { return mAudioHardware; } + status_t startRecord(RecordTrack* recordTrack); + void stopRecord(RecordTrack* recordTrack); mutable Mutex mHardwareLock; mutable Mutex mLock; + mutable Mutex mOutputLock; mutable Condition mWaitWorkCV; DefaultKeyedVector< pid_t, wp<Client> > mClients; SortedVector< wp<Track> > mActiveTracks; @@ -465,15 +460,19 @@ private: bool mMasterMute; stream_type_t mStreamTypes[AudioTrack::NUM_STREAM_TYPES]; + AudioMixer* mHardwareAudioMixer; + AudioMixer* mA2dpAudioMixer; AudioMixer* mAudioMixer; AudioHardwareInterface* mAudioHardware; + AudioHardwareInterface* mA2dpAudioInterface; + AudioStreamOut* mHardwareOutput; + AudioStreamOut* mA2dpOutput; AudioStreamOut* mOutput; sp<AudioRecordThread> mAudioRecordThread; uint32_t mSampleRate; size_t mFrameCount; int mChannelCount; int mFormat; - int mMixBufferSize; int16_t* mMixBuffer; mutable int mHardwareStatus; nsecs_t mLastWriteTime; diff --git a/libs/audioflinger/AudioHardwareGeneric.cpp b/libs/audioflinger/AudioHardwareGeneric.cpp index b1e5b7f..e6a163b 100644 --- a/libs/audioflinger/AudioHardwareGeneric.cpp +++ b/libs/audioflinger/AudioHardwareGeneric.cpp @@ -2,16 +2,16 @@ ** ** Copyright 2007, 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 +** 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 +** 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 +** 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. */ @@ -68,16 +68,25 @@ status_t AudioHardwareGeneric::standby() } AudioStreamOut* AudioHardwareGeneric::openOutputStream( - int format, int channelCount, uint32_t sampleRate) + int format, int channelCount, uint32_t sampleRate, status_t *status) { AutoMutex lock(mLock); // only one output stream allowed - if (mOutput) return 0; + if (mOutput) { + if (status) { + *status = INVALID_OPERATION; + } + return 0; + } // create new output stream AudioStreamOutGeneric* out = new AudioStreamOutGeneric(); - if (out->set(this, mFd, format, channelCount, sampleRate) == NO_ERROR) { + status_t lStatus = out->set(this, mFd, format, channelCount, sampleRate); + if (status) { + *status = lStatus; + } + if (lStatus == NO_ERROR) { mOutput = out; } else { delete out; @@ -90,16 +99,25 @@ void AudioHardwareGeneric::closeOutputStream(AudioStreamOutGeneric* out) { } AudioStreamIn* AudioHardwareGeneric::openInputStream( - int format, int channelCount, uint32_t sampleRate) + int format, int channelCount, uint32_t sampleRate, status_t *status) { AutoMutex lock(mLock); // only one input stream allowed - if (mInput) return 0; + if (mInput) { + if (status) { + *status = INVALID_OPERATION; + } + return 0; + } // create new output stream AudioStreamInGeneric* in = new AudioStreamInGeneric(); - if (in->set(this, mFd, format, channelCount, sampleRate) == NO_ERROR) { + status_t lStatus = in->set(this, mFd, format, channelCount, sampleRate); + if (status) { + *status = lStatus; + } + if (lStatus == NO_ERROR) { mInput = in; } else { delete in; diff --git a/libs/audioflinger/AudioHardwareGeneric.h b/libs/audioflinger/AudioHardwareGeneric.h index 10cc45d..a2342cd 100644 --- a/libs/audioflinger/AudioHardwareGeneric.h +++ b/libs/audioflinger/AudioHardwareGeneric.h @@ -2,16 +2,16 @@ ** ** Copyright 2007, 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 +** 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 +** 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 +** 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. */ @@ -23,7 +23,7 @@ #include <utils/threads.h> -#include <hardware/AudioHardwareInterface.h> +#include <hardware/AudioHardwareBase.h> namespace android { @@ -47,6 +47,7 @@ public: virtual size_t bufferSize() const { return 4096; } virtual int channelCount() const { return 2; } virtual int format() const { return AudioSystem::PCM_16_BIT; } + virtual uint32_t latency() const { return 0; } virtual status_t setVolume(float volume) { return INVALID_OPERATION; } virtual ssize_t write(const void* buffer, size_t bytes); virtual status_t dump(int fd, const Vector<String16>& args); @@ -76,6 +77,7 @@ public: virtual status_t setGain(float gain) { return INVALID_OPERATION; } virtual ssize_t read(void* buffer, ssize_t bytes); virtual status_t dump(int fd, const Vector<String16>& args); + virtual status_t standby() { return NO_ERROR; } private: AudioHardwareGeneric *mAudioHardware; @@ -84,7 +86,7 @@ private: }; -class AudioHardwareGeneric : public AudioHardwareInterface +class AudioHardwareGeneric : public AudioHardwareBase { public: AudioHardwareGeneric(); @@ -105,12 +107,14 @@ public: virtual AudioStreamOut* openOutputStream( int format=0, int channelCount=0, - uint32_t sampleRate=0); + uint32_t sampleRate=0, + status_t *status=0); virtual AudioStreamIn* openInputStream( int format, int channelCount, - uint32_t sampleRate); + uint32_t sampleRate, + status_t *status); void closeOutputStream(AudioStreamOutGeneric* out); void closeInputStream(AudioStreamInGeneric* in); @@ -120,7 +124,7 @@ protected: private: status_t dumpInternals(int fd, const Vector<String16>& args); - + Mutex mLock; AudioStreamOutGeneric *mOutput; AudioStreamInGeneric *mInput; diff --git a/libs/audioflinger/AudioHardwareInterface.cpp b/libs/audioflinger/AudioHardwareInterface.cpp index 7387b3d..ac76a19 100644 --- a/libs/audioflinger/AudioHardwareInterface.cpp +++ b/libs/audioflinger/AudioHardwareInterface.cpp @@ -26,7 +26,7 @@ #include "AudioHardwareStub.h" #include "AudioHardwareGeneric.h" -// #define DUMP_FLINGER_OUT // if defined allows recording samples in a file +//#define DUMP_FLINGER_OUT // if defined allows recording samples in a file #ifdef DUMP_FLINGER_OUT #include "AudioDumpInterface.h" #endif @@ -54,6 +54,7 @@ static const char* routeStrings[] = "SPEAKER ", "BLUETOOTH ", "HEADSET " + "BLUETOOTH_A2DP " }; static const char* routeNone = "NONE"; @@ -115,24 +116,10 @@ AudioHardwareInterface* AudioHardwareInterface::create() // This code adds a record of buffers in a file to write calls made by AudioFlinger. // It replaces the current AudioHardwareInterface object by an intermediate one which // will record buffers in a file (after sending them to hardware) for testing purpose. - // This feature is enabled by defining symbol DUMP_FLINGER_OUT and setting environement - // "audioflinger.dump = 1". The output file is "tmp/FlingerOut.pcm". Pause are not recorded - // in the file. + // This feature is enabled by defining symbol DUMP_FLINGER_OUT. + // The output file is FLINGER_DUMP_NAME. Pause are not recorded in the file. - // read dump mode - property_get("audioflinger.dump", value, "0"); - switch(value[0]) { - case '1': - LOGV("Dump mode"); - hw = new AudioDumpInterface(hw); // replace interface - return hw; - break; - case '0': - default: - LOGV("No Dump mode"); - return hw; - break; - } + hw = new AudioDumpInterface(hw); // replace interface #endif return hw; } @@ -143,7 +130,7 @@ AudioStreamOut::~AudioStreamOut() AudioStreamIn::~AudioStreamIn() {} -AudioHardwareInterface::AudioHardwareInterface() +AudioHardwareBase::AudioHardwareBase() { // force a routing update on initialization memset(&mRoutes, 0, sizeof(mRoutes)); @@ -151,7 +138,7 @@ AudioHardwareInterface::AudioHardwareInterface() } // generics for audio routing - the real work is done in doRouting -status_t AudioHardwareInterface::setRouting(int mode, uint32_t routes) +status_t AudioHardwareBase::setRouting(int mode, uint32_t routes) { #if LOG_ROUTING_CALLS LOGD("setRouting: mode=%s, routes=[%s]", displayMode(mode), displayRoutes(routes)); @@ -173,7 +160,7 @@ status_t AudioHardwareInterface::setRouting(int mode, uint32_t routes) return doRouting(); } -status_t AudioHardwareInterface::getRouting(int mode, uint32_t* routes) +status_t AudioHardwareBase::getRouting(int mode, uint32_t* routes) { if (mode == AudioSystem::MODE_CURRENT) mode = mMode; @@ -187,7 +174,7 @@ status_t AudioHardwareInterface::getRouting(int mode, uint32_t* routes) return NO_ERROR; } -status_t AudioHardwareInterface::setMode(int mode) +status_t AudioHardwareBase::setMode(int mode) { #if LOG_ROUTING_CALLS LOGD("setMode(%s)", displayMode(mode)); @@ -204,25 +191,45 @@ status_t AudioHardwareInterface::setMode(int mode) return doRouting(); } -status_t AudioHardwareInterface::getMode(int* mode) +status_t AudioHardwareBase::getMode(int* mode) { // Implement: set audio routing *mode = mMode; return NO_ERROR; } -status_t AudioHardwareInterface::setParameter(const char* key, const char* value) +status_t AudioHardwareBase::setParameter(const char* key, const char* value) { // default implementation is to ignore return NO_ERROR; } -status_t AudioHardwareInterface::dumpState(int fd, const Vector<String16>& args) + +// default implementation +size_t AudioHardwareBase::getInputBufferSize(uint32_t sampleRate, int format, int channelCount) +{ + if (sampleRate != 8000) { + LOGW("getInputBufferSize bad sampling rate: %d", sampleRate); + return 0; + } + if (format != AudioSystem::PCM_16_BIT) { + LOGW("getInputBufferSize bad format: %d", format); + return 0; + } + if (channelCount != 1) { + LOGW("getInputBufferSize bad channel count: %d", channelCount); + return 0; + } + + return 320; +} + +status_t AudioHardwareBase::dumpState(int fd, const Vector<String16>& args) { const size_t SIZE = 256; char buffer[SIZE]; String8 result; - snprintf(buffer, SIZE, "AudioHardwareInterface::dumpState\n"); + snprintf(buffer, SIZE, "AudioHardwareBase::dumpState\n"); result.append(buffer); snprintf(buffer, SIZE, "\tmMode: %d\n", mMode); result.append(buffer); diff --git a/libs/audioflinger/AudioHardwareStub.cpp b/libs/audioflinger/AudioHardwareStub.cpp index 0046db8..d309902 100644 --- a/libs/audioflinger/AudioHardwareStub.cpp +++ b/libs/audioflinger/AudioHardwareStub.cpp @@ -2,16 +2,16 @@ ** ** Copyright 2007, 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 +** 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 +** 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 +** 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. */ @@ -47,20 +47,28 @@ status_t AudioHardwareStub::standby() } AudioStreamOut* AudioHardwareStub::openOutputStream( - int format, int channelCount, uint32_t sampleRate) + int format, int channelCount, uint32_t sampleRate, status_t *status) { AudioStreamOutStub* out = new AudioStreamOutStub(); - if (out->set(format, channelCount, sampleRate) == NO_ERROR) + status_t lStatus = out->set(format, channelCount, sampleRate); + if (status) { + *status = lStatus; + } + if (lStatus == NO_ERROR) return out; delete out; return 0; } AudioStreamIn* AudioHardwareStub::openInputStream( - int format, int channelCount, uint32_t sampleRate) + int format, int channelCount, uint32_t sampleRate, status_t *status) { AudioStreamInStub* in = new AudioStreamInStub(); - if (in->set(format, channelCount, sampleRate) == NO_ERROR) + status_t lStatus = in->set(format, channelCount, sampleRate); + if (status) { + *status = lStatus; + } + if (lStatus == NO_ERROR) return in; delete in; return 0; @@ -102,7 +110,7 @@ status_t AudioStreamOutStub::set(int format, int channels, uint32_t rate) if (format == 0) format = AudioSystem::PCM_16_BIT; if (channels == 0) channels = channelCount(); if (rate == 0) rate = sampleRate(); - + if ((format == AudioSystem::PCM_16_BIT) && (channels == channelCount()) && (rate == sampleRate())) @@ -129,7 +137,7 @@ status_t AudioStreamOutStub::dump(int fd, const Vector<String16>& args) snprintf(buffer, SIZE, "\tformat: %d\n", format()); result.append(buffer); ::write(fd, result.string(), result.size()); - return NO_ERROR; + return NO_ERROR; } // ---------------------------------------------------------------------------- diff --git a/libs/audioflinger/AudioHardwareStub.h b/libs/audioflinger/AudioHardwareStub.h index 1a61552..5316d60 100644 --- a/libs/audioflinger/AudioHardwareStub.h +++ b/libs/audioflinger/AudioHardwareStub.h @@ -2,16 +2,16 @@ ** ** Copyright 2007, 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 +** 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 +** 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 +** 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. */ @@ -21,7 +21,7 @@ #include <stdint.h> #include <sys/types.h> -#include <hardware/AudioHardwareInterface.h> +#include <hardware/AudioHardwareBase.h> namespace android { @@ -34,6 +34,7 @@ public: virtual size_t bufferSize() const { return 4096; } virtual int channelCount() const { return 2; } virtual int format() const { return AudioSystem::PCM_16_BIT; } + virtual uint32_t latency() const { return 0; } virtual status_t setVolume(float volume) { return NO_ERROR; } virtual ssize_t write(const void* buffer, size_t bytes); virtual status_t dump(int fd, const Vector<String16>& args); @@ -49,9 +50,10 @@ public: virtual status_t setGain(float gain) { return NO_ERROR; } virtual ssize_t read(void* buffer, ssize_t bytes); virtual status_t dump(int fd, const Vector<String16>& args); + virtual status_t standby() { return NO_ERROR; } }; -class AudioHardwareStub : public AudioHardwareInterface +class AudioHardwareStub : public AudioHardwareBase { public: AudioHardwareStub(); @@ -72,12 +74,14 @@ public: virtual AudioStreamOut* openOutputStream( int format=0, int channelCount=0, - uint32_t sampleRate=0); + uint32_t sampleRate=0, + status_t *status=0); virtual AudioStreamIn* openInputStream( int format, int channelCount, - uint32_t sampleRate); + uint32_t sampleRate, + status_t *status); protected: virtual status_t doRouting() { return NO_ERROR; } diff --git a/libs/audioflinger/AudioMixer.cpp b/libs/audioflinger/AudioMixer.cpp index 9f1b17f..b03467f 100644 --- a/libs/audioflinger/AudioMixer.cpp +++ b/libs/audioflinger/AudioMixer.cpp @@ -2,16 +2,16 @@ ** ** Copyright 2007, 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 +** 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 +** 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 +** 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. */ @@ -247,8 +247,8 @@ inline void AudioMixer::track_t::adjustVolumeRamp() { for (int i=0 ; i<2 ; i++) { - if (((volumeInc[i]>0) && ((prevVolume[i]>>16) >= volume[i])) || - ((volumeInc[i]<0) && ((prevVolume[i]>>16) <= volume[i]))) { + if (((volumeInc[i]>0) && (((prevVolume[i]+volumeInc[i])>>16) >= volume[i])) || + ((volumeInc[i]<0) && (((prevVolume[i]+volumeInc[i])>>16) <= volume[i]))) { volumeInc[i] = 0; prevVolume[i] = volume[i]<<16; } @@ -307,7 +307,7 @@ void AudioMixer::process__validate(state_t* state, void* output) n |= NEEDS_CHANNEL_1 + t.channelCount - 1; n |= NEEDS_FORMAT_16; n |= t.doesResample() ? NEEDS_RESAMPLE_ENABLED : NEEDS_RESAMPLE_DISABLED; - + if (t.volumeInc[0]|t.volumeInc[1]) { volumeRamp = 1; } else if (!t.doesResample() && t.volumeRL == 0) { @@ -370,7 +370,7 @@ void AudioMixer::process__validate(state_t* state, void* output) state->hook(state, output); - // Now that the volume ramp has been done, set optimal state and + // Now that the volume ramp has been done, set optimal state and // track hooks for subsequent mixer process if (countActiveTracks) { int allMuted = 1; @@ -397,7 +397,7 @@ void AudioMixer::process__validate(state_t* state, void* output) } } -static inline +static inline int32_t mulAdd(int16_t in, int16_t v, int32_t a) { #if defined(__arm__) && !defined(__thumb__) @@ -412,7 +412,7 @@ int32_t mulAdd(int16_t in, int16_t v, int32_t a) #endif } -static inline +static inline int32_t mul(int16_t in, int16_t v) { #if defined(__arm__) && !defined(__thumb__) @@ -427,7 +427,7 @@ int32_t mul(int16_t in, int16_t v) #endif } -static inline +static inline int32_t mulAddRL(int left, uint32_t inRL, uint32_t vRL, int32_t a) { #if defined(__arm__) && !defined(__thumb__) @@ -453,7 +453,7 @@ int32_t mulAddRL(int left, uint32_t inRL, uint32_t vRL, int32_t a) #endif } -static inline +static inline int32_t mulRL(int left, uint32_t inRL, uint32_t vRL) { #if defined(__arm__) && !defined(__thumb__) @@ -513,7 +513,7 @@ void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, i //LOGD("[0] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", // t, vlInc/65536.0f, vl/65536.0f, t->volume[0], // (vl + vlInc*frameCount)/65536.0f, frameCount); - + // ramp volume do { *out++ += (vl >> 16) * (*temp++ >> 12); @@ -548,7 +548,7 @@ void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount vl += vlInc; vr += vrInc; } while (--frameCount); - + t->prevVolume[0] = vl; t->prevVolume[1] = vr; t->adjustVolumeRamp(); @@ -590,7 +590,7 @@ void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, vl += vlInc; vr += vrInc; } while (--frameCount); - + t->prevVolume[0] = vl; t->prevVolume[1] = vr; t->adjustVolumeRamp(); @@ -609,7 +609,7 @@ void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, t->in = in; } -inline +inline void AudioMixer::ditherAndClamp(int32_t* out, int32_t const *sums, size_t c) { for (size_t i=0 ; i<c ; i++) { @@ -633,8 +633,12 @@ void AudioMixer::process__nop(state_t* state, void* output) const int i = 31 - __builtin_clz(en); en &= ~(1<<i); track_t& t = state->tracks[i]; - t.bufferProvider->getNextBuffer(&t.buffer); - if (t.buffer.raw) { + size_t outFrames = state->frameCount; + while (outFrames) { + t.buffer.frameCount = outFrames; + t.bufferProvider->getNextBuffer(&t.buffer); + if (!t.buffer.raw) break; + outFrames -= t.buffer.frameCount; t.bufferProvider->releaseBuffer(&t.buffer); } } @@ -652,12 +656,14 @@ void AudioMixer::process__genericNoResampling(state_t* state, void* output) const int i = 31 - __builtin_clz(en); en &= ~(1<<i); track_t& t = state->tracks[i]; + t.buffer.frameCount = state->frameCount; t.bufferProvider->getNextBuffer(&t.buffer); + t.frameCount = t.buffer.frameCount; t.in = t.buffer.raw; // t.in == NULL can happen if the track was flushed just after having // been enabled for mixing. if (t.in == NULL) - enabledTracks &= ~(1<<i); + enabledTracks &= ~(1<<i); } // this assumes output 16 bits stereo, no resampling @@ -671,12 +677,31 @@ void AudioMixer::process__genericNoResampling(state_t* state, void* output) const int i = 31 - __builtin_clz(en); en &= ~(1<<i); track_t& t = state->tracks[i]; - (t.hook)(&t, outTemp, BLOCKSIZE, state->resampleTemp); + size_t outFrames = BLOCKSIZE; + + while (outFrames) { + size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount; + if (inFrames) { + (t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp); + t.frameCount -= inFrames; + outFrames -= inFrames; + } + if (t.frameCount == 0 && outFrames) { + t.bufferProvider->releaseBuffer(&t.buffer); + t.buffer.frameCount = numFrames - (BLOCKSIZE - outFrames); + t.bufferProvider->getNextBuffer(&t.buffer); + t.in = t.buffer.raw; + if (t.in == NULL) { + enabledTracks &= ~(1<<i); + break; + } + t.frameCount = t.buffer.frameCount; + } + } } ditherAndClamp(out, outTemp, BLOCKSIZE); out += BLOCKSIZE; - numFrames -= BLOCKSIZE; } while (numFrames); @@ -713,12 +738,19 @@ void AudioMixer::process__genericResampling(state_t* state, void* output) if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) { (t.hook)(&t, outTemp, numFrames, state->resampleTemp); } else { - t.bufferProvider->getNextBuffer(&t.buffer); - t.in = t.buffer.raw; - // t.in == NULL can happen if the track was flushed just after having - // been enabled for mixing. - if (t.in) { - (t.hook)(&t, outTemp, numFrames, state->resampleTemp); + + size_t outFrames = numFrames; + + while (outFrames) { + t.buffer.frameCount = outFrames; + t.bufferProvider->getNextBuffer(&t.buffer); + t.in = t.buffer.raw; + // t.in == NULL can happen if the track was flushed just after having + // been enabled for mixing. + if (t.in == NULL) break; + + (t.hook)(&t, outTemp + (numFrames-outFrames)*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp); + outFrames -= t.buffer.frameCount; t.bufferProvider->releaseBuffer(&t.buffer); } } @@ -734,45 +766,51 @@ void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, void* const track_t& t = state->tracks[i]; AudioBufferProvider::Buffer& b(t.buffer); - t.bufferProvider->getNextBuffer(&b); - int16_t const *in = t.buffer.i16; - - // in == NULL can happen if the track was flushed just after having - // been enabled for mixing. - if (in == NULL) { - memset(output, 0, state->frameCount*MAX_NUM_CHANNELS*sizeof(int16_t)); - return; - } - + int32_t* out = static_cast<int32_t*>(output); size_t numFrames = state->frameCount; + const int16_t vl = t.volume[0]; const int16_t vr = t.volume[1]; const uint32_t vrl = t.volumeRL; - if (UNLIKELY(uint32_t(vl) > UNITY_GAIN || uint32_t(vr) > UNITY_GAIN)) { - // volume is boosted, so we might need to clamp even though - // we process only one track. - do { - uint32_t rl = *reinterpret_cast<uint32_t const *>(in); - in += 2; - int32_t l = mulRL(1, rl, vrl) >> 12; - int32_t r = mulRL(0, rl, vrl) >> 12; - // clamping... - l = clamp16(l); - r = clamp16(r); - *out++ = (r<<16) | (l & 0xFFFF); - } while (--numFrames); - } else { - do { - uint32_t rl = *reinterpret_cast<uint32_t const *>(in); - in += 2; - int32_t l = mulRL(1, rl, vrl) >> 12; - int32_t r = mulRL(0, rl, vrl) >> 12; - *out++ = (r<<16) | (l & 0xFFFF); - } while (--numFrames); - } + while (numFrames) { + b.frameCount = numFrames; + t.bufferProvider->getNextBuffer(&b); + int16_t const *in = b.i16; - t.bufferProvider->releaseBuffer(&b); + // in == NULL can happen if the track was flushed just after having + // been enabled for mixing. + if (in == NULL) { + memset(out, 0, numFrames*MAX_NUM_CHANNELS*sizeof(int16_t)); + return; + } + size_t outFrames = b.frameCount; + + if (UNLIKELY(uint32_t(vl) > UNITY_GAIN || uint32_t(vr) > UNITY_GAIN)) { + // volume is boosted, so we might need to clamp even though + // we process only one track. + do { + uint32_t rl = *reinterpret_cast<uint32_t const *>(in); + in += 2; + int32_t l = mulRL(1, rl, vrl) >> 12; + int32_t r = mulRL(0, rl, vrl) >> 12; + // clamping... + l = clamp16(l); + r = clamp16(r); + *out++ = (r<<16) | (l & 0xFFFF); + } while (--outFrames); + } else { + do { + uint32_t rl = *reinterpret_cast<uint32_t const *>(in); + in += 2; + int32_t l = mulRL(1, rl, vrl) >> 12; + int32_t r = mulRL(0, rl, vrl) >> 12; + *out++ = (r<<16) | (l & 0xFFFF); + } while (--outFrames); + } + numFrames -= b.frameCount; + t.bufferProvider->releaseBuffer(&b); + } } // 2 tracks is also a common case @@ -784,71 +822,89 @@ void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, void i = 31 - __builtin_clz(en); const track_t& t0 = state->tracks[i]; AudioBufferProvider::Buffer& b0(t0.buffer); - t0.bufferProvider->getNextBuffer(&b0); en &= ~(1<<i); i = 31 - __builtin_clz(en); const track_t& t1 = state->tracks[i]; AudioBufferProvider::Buffer& b1(t1.buffer); - t1.bufferProvider->getNextBuffer(&b1); - + int16_t const *in0; const int16_t vl0 = t0.volume[0]; const int16_t vr0 = t0.volume[1]; + size_t frameCount0 = 0; + int16_t const *in1; const int16_t vl1 = t1.volume[0]; const int16_t vr1 = t1.volume[1]; - size_t numFrames = state->frameCount; + size_t frameCount1 = 0; + int32_t* out = static_cast<int32_t*>(output); - - // t0/1.buffer.i16 == NULL can happen if the track was flushed just after having - // been enabled for mixing. - if (t0.buffer.i16 != NULL) { - in0 = t0.buffer.i16; - if (t1.buffer.i16 != NULL) { - in1 = t1.buffer.i16; - } else { - in1 = new int16_t[MAX_NUM_CHANNELS * state->frameCount]; - memset((void *)in1, 0, state->frameCount*MAX_NUM_CHANNELS*sizeof(int16_t)); + size_t numFrames = state->frameCount; + int16_t const *buff = NULL; + + + while (numFrames) { + + if (frameCount0 == 0) { + b0.frameCount = numFrames; + t0.bufferProvider->getNextBuffer(&b0); + if (b0.i16 == NULL) { + if (buff == NULL) { + buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount]; + } + in0 = buff; + b0.frameCount = numFrames; + } else { + in0 = b0.i16; + } + frameCount0 = b0.frameCount; } - } else { - in0 = new int16_t[MAX_NUM_CHANNELS * state->frameCount]; - memset((void *)in0, 0, state->frameCount*MAX_NUM_CHANNELS*sizeof(int16_t)); - if (t1.buffer.i16 != NULL) { - in1 = t1.buffer.i16; - } else { - in1 = in0; + if (frameCount1 == 0) { + b1.frameCount = numFrames; + t1.bufferProvider->getNextBuffer(&b1); + if (b1.i16 == NULL) { + if (buff == NULL) { + buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount]; + } + in1 = buff; + b1.frameCount = numFrames; + } else { + in1 = b1.i16; + } + frameCount1 = b1.frameCount; } - } - - do { - int32_t l0 = *in0++; - int32_t r0 = *in0++; - l0 = mul(l0, vl0); - r0 = mul(r0, vr0); - int32_t l = *in1++; - int32_t r = *in1++; - l = mulAdd(l, vl1, l0) >> 12; - r = mulAdd(r, vr1, r0) >> 12; - // clamping... - l = clamp16(l); - r = clamp16(r); - *out++ = (r<<16) | (l & 0xFFFF); - } while (--numFrames); + + size_t outFrames = frameCount0 < frameCount1?frameCount0:frameCount1; - - if (t0.buffer.i16 != NULL) { - t0.bufferProvider->releaseBuffer(&b0); - if (t1.buffer.i16 != NULL) { - t1.bufferProvider->releaseBuffer(&b1); - } else { - delete [] in1; + numFrames -= outFrames; + frameCount0 -= outFrames; + frameCount1 -= outFrames; + + do { + int32_t l0 = *in0++; + int32_t r0 = *in0++; + l0 = mul(l0, vl0); + r0 = mul(r0, vr0); + int32_t l = *in1++; + int32_t r = *in1++; + l = mulAdd(l, vl1, l0) >> 12; + r = mulAdd(r, vr1, r0) >> 12; + // clamping... + l = clamp16(l); + r = clamp16(r); + *out++ = (r<<16) | (l & 0xFFFF); + } while (--outFrames); + + if (frameCount0 == 0) { + t0.bufferProvider->releaseBuffer(&b0); } - } else { - delete [] in0; - if (t1.buffer.i16 != NULL) { + if (frameCount1 == 0) { t1.bufferProvider->releaseBuffer(&b1); } + } + + if (buff != NULL) { + delete [] buff; } } diff --git a/libs/audioflinger/AudioMixer.h b/libs/audioflinger/AudioMixer.h index 9ca109f..72ca28a 100644 --- a/libs/audioflinger/AudioMixer.h +++ b/libs/audioflinger/AudioMixer.h @@ -2,16 +2,16 @@ ** ** Copyright 2007, 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 +** 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 +** 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 +** 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. */ @@ -130,7 +130,7 @@ private: int32_t volumeInc[2]; - uint16_t reserved; + uint16_t frameCount; uint8_t channelCount : 4; uint8_t enabled : 1; diff --git a/libs/audioflinger/AudioResampler.cpp b/libs/audioflinger/AudioResampler.cpp index c93ead3..5dabacb 100644 --- a/libs/audioflinger/AudioResampler.cpp +++ b/libs/audioflinger/AudioResampler.cpp @@ -14,17 +14,23 @@ * limitations under the License. */ +#define LOG_TAG "AudioResampler" +//#define LOG_NDEBUG 0 + #include <stdint.h> #include <stdlib.h> #include <sys/types.h> #include <cutils/log.h> #include <cutils/properties.h> - #include "AudioResampler.h" #include "AudioResamplerSinc.h" #include "AudioResamplerCubic.h" namespace android { + +#ifdef __ARM_ARCH_5E__ // optimized asm option + #define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1 +#endif // __ARM_ARCH_5E__ // ---------------------------------------------------------------------------- class AudioResamplerOrder1 : public AudioResampler { @@ -46,6 +52,15 @@ private: AudioBufferProvider* provider); void resampleStereo16(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider); +#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 + void AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, + size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, + uint32_t &phaseFraction, uint32_t phaseIncrement); + void AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, + size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, + uint32_t &phaseFraction, uint32_t phaseIncrement); +#endif // ASM_ARM_RESAMP1 + static inline int32_t Interp(int32_t x0, int32_t x1, uint32_t f) { return x0 + (((x1 - x0) * (int32_t)(f >> kPreInterpShift)) >> kNumInterpBits); } @@ -73,20 +88,23 @@ AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount, if (quality == DEFAULT) quality = LOW_QUALITY; - + switch (quality) { default: case LOW_QUALITY: + LOGV("Create linear Resampler"); resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate); break; case MED_QUALITY: + LOGV("Create cubic Resampler"); resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate); break; case HIGH_QUALITY: + LOGV("Create sinc Resampler"); resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate); break; } - + // initialize resampler resampler->init(); return resampler; @@ -103,10 +121,10 @@ AudioResampler::AudioResampler(int bitDepth, int inChannelCount, inChannelCount); // LOG_ASSERT(0); } - + // initialize common members mVolume[0] = mVolume[1] = 0; - mBuffer.raw = NULL; + mBuffer.frameCount = 0; // save format for quick lookup if (inChannelCount == 1) { @@ -160,19 +178,31 @@ void AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount, uint32_t phaseIncrement = mPhaseIncrement; size_t outputIndex = 0; size_t outputSampleCount = outFrameCount * 2; + size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate; // LOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d\n", - // outFrameCount, inputIndex, phaseFraction, phaseIncrement); + // outFrameCount, inputIndex, phaseFraction, phaseIncrement); while (outputIndex < outputSampleCount) { // buffer is empty, fetch a new one - if (mBuffer.raw == NULL) { + while (mBuffer.frameCount == 0) { + mBuffer.frameCount = inFrameCount; provider->getNextBuffer(&mBuffer); - if (mBuffer.raw == NULL) - break; + if (mBuffer.raw == NULL) { + goto resampleStereo16_exit; + } + // LOGE("New buffer fetched: %d frames\n", mBuffer.frameCount); + if (mBuffer.frameCount > inputIndex) break; + + inputIndex -= mBuffer.frameCount; + mX0L = mBuffer.i16[mBuffer.frameCount*2-2]; + mX0R = mBuffer.i16[mBuffer.frameCount*2-1]; + provider->releaseBuffer(&mBuffer); + // mBuffer.frameCount == 0 now so we reload a new buffer } + int16_t *in = mBuffer.i16; // handle boundary case @@ -187,34 +217,47 @@ void AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount, // process input samples // LOGE("general case\n"); - while (outputIndex < outputSampleCount) { + +#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 + if (inputIndex + 2 < mBuffer.frameCount) { + int32_t* maxOutPt; + int32_t maxInIdx; + + maxOutPt = out + (outputSampleCount - 2); // 2 because 2 frames per loop + maxInIdx = mBuffer.frameCount - 2; + AsmStereo16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr, + phaseFraction, phaseIncrement); + } +#endif // ASM_ARM_RESAMP1 + + while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) { out[outputIndex++] += vl * Interp(in[inputIndex*2-2], in[inputIndex*2], phaseFraction); out[outputIndex++] += vr * Interp(in[inputIndex*2-1], in[inputIndex*2+1], phaseFraction); Advance(&inputIndex, &phaseFraction, phaseIncrement); - if (inputIndex >= mBuffer.frameCount) - break; } + // LOGE("loop done - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex); // if done with buffer, save samples if (inputIndex >= mBuffer.frameCount) { inputIndex -= mBuffer.frameCount; - // LOGE("buffer done, new input index", inputIndex); + // LOGE("buffer done, new input index %d", inputIndex); mX0L = mBuffer.i16[mBuffer.frameCount*2-2]; mX0R = mBuffer.i16[mBuffer.frameCount*2-1]; provider->releaseBuffer(&mBuffer); - // verify that the releaseBuffer NULLS the buffer pointer - // LOG_ASSERT(mBuffer.raw == NULL); + // verify that the releaseBuffer resets the buffer frameCount + // LOG_ASSERT(mBuffer.frameCount == 0); } } // LOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex); +resampleStereo16_exit: // save state mInputIndex = inputIndex; mPhaseFraction = phaseFraction; @@ -231,18 +274,27 @@ void AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount, uint32_t phaseIncrement = mPhaseIncrement; size_t outputIndex = 0; size_t outputSampleCount = outFrameCount * 2; + size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate; // LOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d\n", // outFrameCount, inputIndex, phaseFraction, phaseIncrement); - while (outputIndex < outputSampleCount) { - // buffer is empty, fetch a new one - if (mBuffer.raw == NULL) { + while (mBuffer.frameCount == 0) { + mBuffer.frameCount = inFrameCount; provider->getNextBuffer(&mBuffer); - if (mBuffer.raw == NULL) - break; + if (mBuffer.raw == NULL) { + mInputIndex = inputIndex; + mPhaseFraction = phaseFraction; + goto resampleMono16_exit; + } // LOGE("New buffer fetched: %d frames\n", mBuffer.frameCount); + if (mBuffer.frameCount > inputIndex) break; + + inputIndex -= mBuffer.frameCount; + mX0L = mBuffer.i16[mBuffer.frameCount-1]; + provider->releaseBuffer(&mBuffer); + // mBuffer.frameCount == 0 now so we reload a new buffer } int16_t *in = mBuffer.i16; @@ -259,38 +311,284 @@ void AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount, // process input samples // LOGE("general case\n"); - while (outputIndex < outputSampleCount) { + +#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 + if (inputIndex + 2 < mBuffer.frameCount) { + int32_t* maxOutPt; + int32_t maxInIdx; + + maxOutPt = out + (outputSampleCount - 2); + maxInIdx = (int32_t)mBuffer.frameCount - 2; + AsmMono16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr, + phaseFraction, phaseIncrement); + } +#endif // ASM_ARM_RESAMP1 + + while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) { int32_t sample = Interp(in[inputIndex-1], in[inputIndex], phaseFraction); out[outputIndex++] += vl * sample; out[outputIndex++] += vr * sample; Advance(&inputIndex, &phaseFraction, phaseIncrement); - if (inputIndex >= mBuffer.frameCount) - break; } + + // LOGE("loop done - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex); // if done with buffer, save samples if (inputIndex >= mBuffer.frameCount) { inputIndex -= mBuffer.frameCount; - // LOGE("buffer done, new input index", inputIndex); + // LOGE("buffer done, new input index %d", inputIndex); mX0L = mBuffer.i16[mBuffer.frameCount-1]; provider->releaseBuffer(&mBuffer); - // verify that the releaseBuffer NULLS the buffer pointer - // LOG_ASSERT(mBuffer.raw == NULL); + // verify that the releaseBuffer resets the buffer frameCount + // LOG_ASSERT(mBuffer.frameCount == 0); } } // LOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex); +resampleMono16_exit: // save state mInputIndex = inputIndex; mPhaseFraction = phaseFraction; } +#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 + +/******************************************************************* +* +* AsmMono16Loop +* asm optimized monotonic loop version; one loop is 2 frames +* Input: +* in : pointer on input samples +* maxOutPt : pointer on first not filled +* maxInIdx : index on first not used +* outputIndex : pointer on current output index +* out : pointer on output buffer +* inputIndex : pointer on current input index +* vl, vr : left and right gain +* phaseFraction : pointer on current phase fraction +* phaseIncrement +* Ouput: +* outputIndex : +* out : updated buffer +* inputIndex : index of next to use +* phaseFraction : phase fraction for next interpolation +* +*******************************************************************/ +void AudioResamplerOrder1::AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, + size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, + uint32_t &phaseFraction, uint32_t phaseIncrement) +{ +#define MO_PARAM5 "36" // offset of parameter 5 (outputIndex) + + asm( + "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n" + // get parameters + " ldr r6, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction + " ldr r6, [r6]\n" // phaseFraction + " ldr r7, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex + " ldr r7, [r7]\n" // inputIndex + " ldr r8, [sp, #" MO_PARAM5 " + 4]\n" // out + " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex + " ldr r0, [r0]\n" // outputIndex + " add r8, r0, asl #2\n" // curOut + " ldr r9, [sp, #" MO_PARAM5 " + 24]\n" // phaseIncrement + " ldr r10, [sp, #" MO_PARAM5 " + 12]\n" // vl + " ldr r11, [sp, #" MO_PARAM5 " + 16]\n" // vr + + // r0 pin, x0, Samp + + // r1 in + // r2 maxOutPt + // r3 maxInIdx + + // r4 x1, i1, i3, Out1 + // r5 out0 + + // r6 frac + // r7 inputIndex + // r8 curOut + + // r9 inc + // r10 vl + // r11 vr + + // r12 + // r13 sp + // r14 + + // the following loop works on 2 frames + + ".Y4L01:\n" + " cmp r8, r2\n" // curOut - maxCurOut + " bcs .Y4L02\n" + +#define MO_ONE_FRAME \ + " add r0, r1, r7, asl #1\n" /* in + inputIndex */\ + " ldrsh r4, [r0]\n" /* in[inputIndex] */\ + " ldr r5, [r8]\n" /* out[outputIndex] */\ + " ldrsh r0, [r0, #-2]\n" /* in[inputIndex-1] */\ + " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\ + " sub r4, r4, r0\n" /* in[inputIndex] - in[inputIndex-1] */\ + " mov r4, r4, lsl #2\n" /* <<2 */\ + " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\ + " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\ + " add r0, r0, r4\n" /* x0 - (..) */\ + " mla r5, r0, r10, r5\n" /* vl*interp + out[] */\ + " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\ + " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\ + " mla r4, r0, r11, r4\n" /* vr*interp + out[] */\ + " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */\ + " str r4, [r8], #4\n" /* out[outputIndex++] = ... */ + + MO_ONE_FRAME // frame 1 + MO_ONE_FRAME // frame 2 + + " cmp r7, r3\n" // inputIndex - maxInIdx + " bcc .Y4L01\n" + ".Y4L02:\n" + + " bic r6, r6, #0xC0000000\n" // phaseFraction & ... + // save modified values + " ldr r0, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction + " str r6, [r0]\n" // phaseFraction + " ldr r0, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex + " str r7, [r0]\n" // inputIndex + " ldr r0, [sp, #" MO_PARAM5 " + 4]\n" // out + " sub r8, r0\n" // curOut - out + " asr r8, #2\n" // new outputIndex + " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex + " str r8, [r0]\n" // save outputIndex + + " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}\n" + ); +} + +/******************************************************************* +* +* AsmStereo16Loop +* asm optimized stereo loop version; one loop is 2 frames +* Input: +* in : pointer on input samples +* maxOutPt : pointer on first not filled +* maxInIdx : index on first not used +* outputIndex : pointer on current output index +* out : pointer on output buffer +* inputIndex : pointer on current input index +* vl, vr : left and right gain +* phaseFraction : pointer on current phase fraction +* phaseIncrement +* Ouput: +* outputIndex : +* out : updated buffer +* inputIndex : index of next to use +* phaseFraction : phase fraction for next interpolation +* +*******************************************************************/ +void AudioResamplerOrder1::AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, + size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, + uint32_t &phaseFraction, uint32_t phaseIncrement) +{ +#define ST_PARAM5 "40" // offset of parameter 5 (outputIndex) + asm( + "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr}\n" + // get parameters + " ldr r6, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction + " ldr r6, [r6]\n" // phaseFraction + " ldr r7, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex + " ldr r7, [r7]\n" // inputIndex + " ldr r8, [sp, #" ST_PARAM5 " + 4]\n" // out + " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex + " ldr r0, [r0]\n" // outputIndex + " add r8, r0, asl #2\n" // curOut + " ldr r9, [sp, #" ST_PARAM5 " + 24]\n" // phaseIncrement + " ldr r10, [sp, #" ST_PARAM5 " + 12]\n" // vl + " ldr r11, [sp, #" ST_PARAM5 " + 16]\n" // vr + + // r0 pin, x0, Samp + + // r1 in + // r2 maxOutPt + // r3 maxInIdx + + // r4 x1, i1, i3, out1 + // r5 out0 + + // r6 frac + // r7 inputIndex + // r8 curOut + + // r9 inc + // r10 vl + // r11 vr + + // r12 temporary + // r13 sp + // r14 + + ".Y5L01:\n" + " cmp r8, r2\n" // curOut - maxCurOut + " bcs .Y5L02\n" + +#define ST_ONE_FRAME \ + " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\ +\ + " add r0, r1, r7, asl #2\n" /* in + 2*inputIndex */\ +\ + " ldrsh r4, [r0]\n" /* in[2*inputIndex] */\ + " ldr r5, [r8]\n" /* out[outputIndex] */\ + " ldrsh r12, [r0, #-4]\n" /* in[2*inputIndex-2] */\ + " sub r4, r4, r12\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\ + " mov r4, r4, lsl #2\n" /* <<2 */\ + " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\ + " add r12, r12, r4\n" /* x0 - (..) */\ + " mla r5, r12, r10, r5\n" /* vl*interp + out[] */\ + " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\ + " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\ +\ + " ldrsh r12, [r0, #+2]\n" /* in[2*inputIndex+1] */\ + " ldrsh r0, [r0, #-2]\n" /* in[2*inputIndex-1] */\ + " sub r12, r12, r0\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\ + " mov r12, r12, lsl #2\n" /* <<2 */\ + " smulwt r12, r12, r6\n" /* (x1-x0)*.. */\ + " add r12, r0, r12\n" /* x0 - (..) */\ + " mla r4, r12, r11, r4\n" /* vr*interp + out[] */\ + " str r4, [r8], #4\n" /* out[outputIndex++] = ... */\ +\ + " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\ + " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */ + + ST_ONE_FRAME // frame 1 + ST_ONE_FRAME // frame 1 + + " cmp r7, r3\n" // inputIndex - maxInIdx + " bcc .Y5L01\n" + ".Y5L02:\n" + + " bic r6, r6, #0xC0000000\n" // phaseFraction & ... + // save modified values + " ldr r0, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction + " str r6, [r0]\n" // phaseFraction + " ldr r0, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex + " str r7, [r0]\n" // inputIndex + " ldr r0, [sp, #" ST_PARAM5 " + 4]\n" // out + " sub r8, r0\n" // curOut - out + " asr r8, #2\n" // new outputIndex + " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex + " str r8, [r0]\n" // save outputIndex + + " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, pc}\n" + ); +} + +#endif // ASM_ARM_RESAMP1 + + // ---------------------------------------------------------------------------- } ; // namespace android diff --git a/libs/audioflinger/AudioResamplerCubic.cpp b/libs/audioflinger/AudioResamplerCubic.cpp index 4f437bf..1d247bd 100644 --- a/libs/audioflinger/AudioResamplerCubic.cpp +++ b/libs/audioflinger/AudioResamplerCubic.cpp @@ -60,9 +60,11 @@ void AudioResamplerCubic::resampleStereo16(int32_t* out, size_t outFrameCount, uint32_t phaseIncrement = mPhaseIncrement; size_t outputIndex = 0; size_t outputSampleCount = outFrameCount * 2; - + size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate; + // fetch first buffer - if (mBuffer.raw == NULL) { + if (mBuffer.frameCount == 0) { + mBuffer.frameCount = inFrameCount; provider->getNextBuffer(&mBuffer); if (mBuffer.raw == NULL) return; @@ -79,7 +81,7 @@ void AudioResamplerCubic::resampleStereo16(int32_t* out, size_t outFrameCount, out[outputIndex++] += vl * interp(&left, x); out[outputIndex++] += vr * interp(&right, x); // out[outputIndex++] += vr * in[inputIndex*2]; - + // increment phase phaseFraction += phaseIncrement; uint32_t indexIncrement = (phaseFraction >> kNumPhaseBits); @@ -92,6 +94,7 @@ void AudioResamplerCubic::resampleStereo16(int32_t* out, size_t outFrameCount, if (inputIndex == mBuffer.frameCount) { inputIndex = 0; provider->releaseBuffer(&mBuffer); + mBuffer.frameCount = inFrameCount; provider->getNextBuffer(&mBuffer); if (mBuffer.raw == NULL) goto save_state; // ugly, but efficient @@ -122,9 +125,11 @@ void AudioResamplerCubic::resampleMono16(int32_t* out, size_t outFrameCount, uint32_t phaseIncrement = mPhaseIncrement; size_t outputIndex = 0; size_t outputSampleCount = outFrameCount * 2; - + size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate; + // fetch first buffer - if (mBuffer.raw == NULL) { + if (mBuffer.frameCount == 0) { + mBuffer.frameCount = inFrameCount; provider->getNextBuffer(&mBuffer); if (mBuffer.raw == NULL) return; @@ -141,7 +146,7 @@ void AudioResamplerCubic::resampleMono16(int32_t* out, size_t outFrameCount, sample = interp(&left, x); out[outputIndex++] += vl * sample; out[outputIndex++] += vr * sample; - + // increment phase phaseFraction += phaseIncrement; uint32_t indexIncrement = (phaseFraction >> kNumPhaseBits); @@ -154,6 +159,7 @@ void AudioResamplerCubic::resampleMono16(int32_t* out, size_t outFrameCount, if (inputIndex == mBuffer.frameCount) { inputIndex = 0; provider->releaseBuffer(&mBuffer); + mBuffer.frameCount = inFrameCount; provider->getNextBuffer(&mBuffer); if (mBuffer.raw == NULL) goto save_state; // ugly, but efficient diff --git a/libs/audioflinger/AudioResamplerSinc.cpp b/libs/audioflinger/AudioResamplerSinc.cpp index e710d16..9e5e254 100644 --- a/libs/audioflinger/AudioResamplerSinc.cpp +++ b/libs/audioflinger/AudioResamplerSinc.cpp @@ -25,18 +25,18 @@ namespace android { * These coeficients are computed with the "fir" utility found in * tools/resampler_tools * TODO: A good optimization would be to transpose this matrix, to take - * better advantage of the data-cache. + * better advantage of the data-cache. */ const int32_t AudioResamplerSinc::mFirCoefsUp[] = { - 0x7fffffff, 0x7f15d078, 0x7c5e0da6, 0x77ecd867, 0x71e2e251, 0x6a6c304a, 0x61be7269, 0x58170412, 0x4db8ab05, 0x42e92ea6, 0x37eee214, 0x2d0e3bb1, 0x22879366, 0x18951e95, 0x0f693d0d, 0x072d2621, - 0x00000000, 0xf9f66655, 0xf51a5fd7, 0xf16bbd84, 0xeee0d9ac, 0xed67a922, 0xece70de6, 0xed405897, 0xee50e505, 0xeff3be30, 0xf203370f, 0xf45a6741, 0xf6d67d53, 0xf957db66, 0xfbc2f647, 0xfe00f2b9, - 0x00000000, 0x01b37218, 0x0313a0c6, 0x041d930d, 0x04d28057, 0x053731b0, 0x05534dff, 0x05309bfd, 0x04da440d, 0x045c1aee, 0x03c1fcdd, 0x03173ef5, 0x02663ae8, 0x01b7f736, 0x0113ec79, 0x007fe6a9, - 0x00000000, 0xff96b229, 0xff44f99f, 0xff0a86be, 0xfee5f803, 0xfed518fd, 0xfed521fd, 0xfee2f4fd, 0xfefb54f8, 0xff1b159b, 0xff3f4203, 0xff6539e0, 0xff8ac502, 0xffae1ddd, 0xffcdf3f9, 0xffe96798, - 0x00000000, 0x00119de6, 0x001e6b7e, 0x0026cb7a, 0x002b4830, 0x002c83d6, 0x002b2a82, 0x0027e67a, 0x002356f9, 0x001e098e, 0x001875e4, 0x0012fbbe, 0x000de2d1, 0x00095c10, 0x00058414, 0x00026636, - 0x00000000, 0xfffe44a9, 0xfffd206d, 0xfffc7b7f, 0xfffc3c8f, 0xfffc4ac2, 0xfffc8f2b, 0xfffcf5c4, 0xfffd6df3, 0xfffdeab2, 0xfffe6275, 0xfffececf, 0xffff2c07, 0xffff788c, 0xffffb471, 0xffffe0f2, - 0x00000000, 0x000013e6, 0x00001f03, 0x00002396, 0x00002399, 0x000020b6, 0x00001c3c, 0x00001722, 0x00001216, 0x00000d81, 0x0000099c, 0x0000067c, 0x00000419, 0x0000025f, 0x00000131, 0x00000070, - 0x00000000, 0xffffffc7, 0xffffffb3, 0xffffffb3, 0xffffffbe, 0xffffffcd, 0xffffffdb, 0xffffffe7, 0xfffffff0, 0xfffffff7, 0xfffffffb, 0xfffffffe, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, - 0x00000000 // this one is needed for lerping the last coefficient + 0x7fffffff, 0x7f15d078, 0x7c5e0da6, 0x77ecd867, 0x71e2e251, 0x6a6c304a, 0x61be7269, 0x58170412, 0x4db8ab05, 0x42e92ea6, 0x37eee214, 0x2d0e3bb1, 0x22879366, 0x18951e95, 0x0f693d0d, 0x072d2621, + 0x00000000, 0xf9f66655, 0xf51a5fd7, 0xf16bbd84, 0xeee0d9ac, 0xed67a922, 0xece70de6, 0xed405897, 0xee50e505, 0xeff3be30, 0xf203370f, 0xf45a6741, 0xf6d67d53, 0xf957db66, 0xfbc2f647, 0xfe00f2b9, + 0x00000000, 0x01b37218, 0x0313a0c6, 0x041d930d, 0x04d28057, 0x053731b0, 0x05534dff, 0x05309bfd, 0x04da440d, 0x045c1aee, 0x03c1fcdd, 0x03173ef5, 0x02663ae8, 0x01b7f736, 0x0113ec79, 0x007fe6a9, + 0x00000000, 0xff96b229, 0xff44f99f, 0xff0a86be, 0xfee5f803, 0xfed518fd, 0xfed521fd, 0xfee2f4fd, 0xfefb54f8, 0xff1b159b, 0xff3f4203, 0xff6539e0, 0xff8ac502, 0xffae1ddd, 0xffcdf3f9, 0xffe96798, + 0x00000000, 0x00119de6, 0x001e6b7e, 0x0026cb7a, 0x002b4830, 0x002c83d6, 0x002b2a82, 0x0027e67a, 0x002356f9, 0x001e098e, 0x001875e4, 0x0012fbbe, 0x000de2d1, 0x00095c10, 0x00058414, 0x00026636, + 0x00000000, 0xfffe44a9, 0xfffd206d, 0xfffc7b7f, 0xfffc3c8f, 0xfffc4ac2, 0xfffc8f2b, 0xfffcf5c4, 0xfffd6df3, 0xfffdeab2, 0xfffe6275, 0xfffececf, 0xffff2c07, 0xffff788c, 0xffffb471, 0xffffe0f2, + 0x00000000, 0x000013e6, 0x00001f03, 0x00002396, 0x00002399, 0x000020b6, 0x00001c3c, 0x00001722, 0x00001216, 0x00000d81, 0x0000099c, 0x0000067c, 0x00000419, 0x0000025f, 0x00000131, 0x00000070, + 0x00000000, 0xffffffc7, 0xffffffb3, 0xffffffb3, 0xffffffbe, 0xffffffcd, 0xffffffdb, 0xffffffe7, 0xfffffff0, 0xfffffff7, 0xfffffffb, 0xfffffffe, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, + 0x00000000 // this one is needed for lerping the last coefficient }; /* @@ -46,20 +46,20 @@ const int32_t AudioResamplerSinc::mFirCoefsUp[] = { * these coefficient from the above by "Stretching" them in time). */ const int32_t AudioResamplerSinc::mFirCoefsDown[] = { - 0x7fffffff, 0x7f55e46d, 0x7d5b4c60, 0x7a1b4b98, 0x75a7fb14, 0x7019f0bd, 0x698f875a, 0x622bfd59, 0x5a167256, 0x5178cc54, 0x487e8e6c, 0x3f53aae8, 0x36235ad4, 0x2d17047b, 0x245539ab, 0x1c00d540, - 0x14383e57, 0x0d14d5ca, 0x06aa910b, 0x0107c38b, 0xfc351654, 0xf835abae, 0xf5076b45, 0xf2a37202, 0xf0fe9faa, 0xf00a3bbd, 0xefb4aa81, 0xefea2b05, 0xf0959716, 0xf1a11e83, 0xf2f6f7a0, 0xf481fff4, - 0xf62e48ce, 0xf7e98ca5, 0xf9a38b4c, 0xfb4e4bfa, 0xfcde456f, 0xfe4a6d30, 0xff8c2fdf, 0x009f5555, 0x0181d393, 0x0233940f, 0x02b62f06, 0x030ca07d, 0x033afa62, 0x03461725, 0x03334f83, 0x030835fa, - 0x02ca59cc, 0x027f12d1, 0x022b570d, 0x01d39a49, 0x017bb78f, 0x0126e414, 0x00d7aaaf, 0x008feec7, 0x0050f584, 0x001b73e3, 0xffefa063, 0xffcd46ed, 0xffb3ddcd, 0xffa29aaa, 0xff988691, 0xff949066, - 0xff959d24, 0xff9a959e, 0xffa27195, 0xffac4011, 0xffb72d2b, 0xffc28569, 0xffcdb706, 0xffd85171, 0xffe20364, 0xffea97e9, 0xfff1f2b2, 0xfff80c06, 0xfffcec92, 0x0000a955, 0x00035fd8, 0x000532cf, - 0x00064735, 0x0006c1f9, 0x0006c62d, 0x000673ba, 0x0005e68f, 0x00053630, 0x000475a3, 0x0003b397, 0x0002fac1, 0x00025257, 0x0001be9e, 0x0001417a, 0x0000dafd, 0x000089eb, 0x00004c28, 0x00001f1d, - 0x00000000, 0xffffec10, 0xffffe0be, 0xffffdbc5, 0xffffdb39, 0xffffdd8b, 0xffffe182, 0xffffe638, 0xffffeb0a, 0xffffef8f, 0xfffff38b, 0xfffff6e3, 0xfffff993, 0xfffffba6, 0xfffffd30, 0xfffffe4a, - 0xffffff09, 0xffffff85, 0xffffffd1, 0xfffffffb, 0x0000000f, 0x00000016, 0x00000015, 0x00000012, 0x0000000d, 0x00000009, 0x00000006, 0x00000003, 0x00000002, 0x00000001, 0x00000000, 0x00000000, - 0x00000000 // this one is needed for lerping the last coefficient + 0x7fffffff, 0x7f55e46d, 0x7d5b4c60, 0x7a1b4b98, 0x75a7fb14, 0x7019f0bd, 0x698f875a, 0x622bfd59, 0x5a167256, 0x5178cc54, 0x487e8e6c, 0x3f53aae8, 0x36235ad4, 0x2d17047b, 0x245539ab, 0x1c00d540, + 0x14383e57, 0x0d14d5ca, 0x06aa910b, 0x0107c38b, 0xfc351654, 0xf835abae, 0xf5076b45, 0xf2a37202, 0xf0fe9faa, 0xf00a3bbd, 0xefb4aa81, 0xefea2b05, 0xf0959716, 0xf1a11e83, 0xf2f6f7a0, 0xf481fff4, + 0xf62e48ce, 0xf7e98ca5, 0xf9a38b4c, 0xfb4e4bfa, 0xfcde456f, 0xfe4a6d30, 0xff8c2fdf, 0x009f5555, 0x0181d393, 0x0233940f, 0x02b62f06, 0x030ca07d, 0x033afa62, 0x03461725, 0x03334f83, 0x030835fa, + 0x02ca59cc, 0x027f12d1, 0x022b570d, 0x01d39a49, 0x017bb78f, 0x0126e414, 0x00d7aaaf, 0x008feec7, 0x0050f584, 0x001b73e3, 0xffefa063, 0xffcd46ed, 0xffb3ddcd, 0xffa29aaa, 0xff988691, 0xff949066, + 0xff959d24, 0xff9a959e, 0xffa27195, 0xffac4011, 0xffb72d2b, 0xffc28569, 0xffcdb706, 0xffd85171, 0xffe20364, 0xffea97e9, 0xfff1f2b2, 0xfff80c06, 0xfffcec92, 0x0000a955, 0x00035fd8, 0x000532cf, + 0x00064735, 0x0006c1f9, 0x0006c62d, 0x000673ba, 0x0005e68f, 0x00053630, 0x000475a3, 0x0003b397, 0x0002fac1, 0x00025257, 0x0001be9e, 0x0001417a, 0x0000dafd, 0x000089eb, 0x00004c28, 0x00001f1d, + 0x00000000, 0xffffec10, 0xffffe0be, 0xffffdbc5, 0xffffdb39, 0xffffdd8b, 0xffffe182, 0xffffe638, 0xffffeb0a, 0xffffef8f, 0xfffff38b, 0xfffff6e3, 0xfffff993, 0xfffffba6, 0xfffffd30, 0xfffffe4a, + 0xffffff09, 0xffffff85, 0xffffffd1, 0xfffffffb, 0x0000000f, 0x00000016, 0x00000015, 0x00000012, 0x0000000d, 0x00000009, 0x00000006, 0x00000003, 0x00000002, 0x00000001, 0x00000000, 0x00000000, + 0x00000000 // this one is needed for lerping the last coefficient }; // ---------------------------------------------------------------------------- -static inline +static inline int32_t mulRL(int left, int32_t in, uint32_t vRL) { #if defined(__arm__) && !defined(__thumb__) @@ -85,7 +85,7 @@ int32_t mulRL(int left, int32_t in, uint32_t vRL) #endif } -static inline +static inline int32_t mulAdd(int16_t in, int32_t v, int32_t a) { #if defined(__arm__) && !defined(__thumb__) @@ -95,12 +95,14 @@ int32_t mulAdd(int16_t in, int32_t v, int32_t a) : [in]"%r"(in), [v]"r"(v), [a]"r"(a) : ); return out; -#else - return a + ((in * int32_t(v))>>16); +#else + return a + in * (v>>16); + // improved precision + // return a + in * (v>>16) + ((in * (v & 0xffff)) >> 16); #endif } -static inline +static inline int32_t mulAddRL(int left, uint32_t inRL, int32_t v, int32_t a) { #if defined(__arm__) && !defined(__thumb__) @@ -119,9 +121,11 @@ int32_t mulAddRL(int left, uint32_t inRL, int32_t v, int32_t a) return out; #else if (left) { - return a + ((int16_t(inRL&0xFFFF) * int32_t(v))>>16); + return a + (int16_t(inRL&0xFFFF) * (v>>16)); + //improved precision + // return a + (int16_t(inRL&0xFFFF) * (v>>16)) + ((int16_t(inRL&0xFFFF) * (v & 0xffff)) >> 16); } else { - return a + ((int16_t(inRL>>16) * int32_t(v))>>16); + return a + (int16_t(inRL>>16) * (v>>16)); } #endif } @@ -129,37 +133,37 @@ int32_t mulAddRL(int left, uint32_t inRL, int32_t v, int32_t a) // ---------------------------------------------------------------------------- AudioResamplerSinc::AudioResamplerSinc(int bitDepth, - int inChannelCount, int32_t sampleRate) - : AudioResampler(bitDepth, inChannelCount, sampleRate), - mState(0) + int inChannelCount, int32_t sampleRate) + : AudioResampler(bitDepth, inChannelCount, sampleRate), + mState(0) { - /* - * Layout of the state buffer for 32 tap: - * - * "present" sample beginning of 2nd buffer - * v v - * 0 01 2 23 3 - * 0 F0 0 F0 F - * [pppppppppppppppInnnnnnnnnnnnnnnnpppppppppppppppInnnnnnnnnnnnnnnn] - * ^ ^ head - * - * p = past samples, convoluted with the (p)ositive side of sinc() - * n = future samples, convoluted with the (n)egative side of sinc() - * r = extra space for implementing the ring buffer - * - */ + /* + * Layout of the state buffer for 32 tap: + * + * "present" sample beginning of 2nd buffer + * v v + * 0 01 2 23 3 + * 0 F0 0 F0 F + * [pppppppppppppppInnnnnnnnnnnnnnnnpppppppppppppppInnnnnnnnnnnnnnnn] + * ^ ^ head + * + * p = past samples, convoluted with the (p)ositive side of sinc() + * n = future samples, convoluted with the (n)egative side of sinc() + * r = extra space for implementing the ring buffer + * + */ - const size_t numCoefs = 2*halfNumCoefs; - const size_t stateSize = numCoefs * inChannelCount * 2; - mState = new int16_t[stateSize]; - memset(mState, 0, sizeof(int16_t)*stateSize); - mImpulse = mState + (halfNumCoefs-1)*inChannelCount; - mRingFull = mImpulse + (numCoefs+1)*inChannelCount; + const size_t numCoefs = 2*halfNumCoefs; + const size_t stateSize = numCoefs * inChannelCount * 2; + mState = new int16_t[stateSize]; + memset(mState, 0, sizeof(int16_t)*stateSize); + mImpulse = mState + (halfNumCoefs-1)*inChannelCount; + mRingFull = mImpulse + (numCoefs+1)*inChannelCount; } AudioResamplerSinc::~AudioResamplerSinc() { - delete [] mState; + delete [] mState; } void AudioResamplerSinc::init() { @@ -168,9 +172,9 @@ void AudioResamplerSinc::init() { void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider) { - mFirCoefs = (mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown; + mFirCoefs = (mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown; - // select the appropriate resampler + // select the appropriate resampler switch (mChannelCount) { case 1: resample<1>(out, outFrameCount, provider); @@ -193,43 +197,68 @@ void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount, uint32_t phaseIncrement = mPhaseIncrement; size_t outputIndex = 0; size_t outputSampleCount = outFrameCount * 2; + size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate; AudioBufferProvider::Buffer& buffer(mBuffer); while (outputIndex < outputSampleCount) { // buffer is empty, fetch a new one - if (buffer.raw == NULL) { + while (buffer.frameCount == 0) { + buffer.frameCount = inFrameCount; provider->getNextBuffer(&buffer); - if (buffer.raw == NULL) - break; - const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits; - if (phaseIndex) { - read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex); + if (buffer.raw == NULL) { + goto resample_exit; } + const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits; + if (phaseIndex == 1) { + // read one frame + read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex); + } else if (phaseIndex == 2) { + // read 2 frames + read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex); + inputIndex++; + if (inputIndex >= mBuffer.frameCount) { + inputIndex -= mBuffer.frameCount; + provider->releaseBuffer(&buffer); + } else { + read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex); + } + } } int16_t *in = buffer.i16; - const size_t frameCount = buffer.frameCount; + const size_t frameCount = buffer.frameCount; - // Always read-in the first samples from the input buffer - int16_t* head = impulse + halfNumCoefs*CHANNELS; - head[0] = in[inputIndex*CHANNELS + 0]; - if (CHANNELS == 2) - head[1] = in[inputIndex*CHANNELS + 1]; + // Always read-in the first samples from the input buffer + int16_t* head = impulse + halfNumCoefs*CHANNELS; + head[0] = in[inputIndex*CHANNELS + 0]; + if (CHANNELS == 2) + head[1] = in[inputIndex*CHANNELS + 1]; // handle boundary case - int32_t l, r; + int32_t l, r; while (outputIndex < outputSampleCount) { - filterCoefficient<CHANNELS>(l, r, phaseFraction, impulse); - out[outputIndex++] = mulRL(1, l, vRL); - out[outputIndex++] = mulRL(0, r, vRL); + filterCoefficient<CHANNELS>(l, r, phaseFraction, impulse); + out[outputIndex++] += 2 * mulRL(1, l, vRL); + out[outputIndex++] += 2 * mulRL(0, r, vRL); - phaseFraction += phaseIncrement; - const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits; - if (phaseIndex) { - inputIndex += phaseIndex; - if (inputIndex >= frameCount) - break; - read<CHANNELS>(impulse, phaseFraction, in, inputIndex); - } + phaseFraction += phaseIncrement; + const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits; + if (phaseIndex == 1) { + inputIndex++; + if (inputIndex >= frameCount) + break; // need a new buffer + read<CHANNELS>(impulse, phaseFraction, in, inputIndex); + } else if(phaseIndex == 2) { // maximum value + inputIndex++; + if (inputIndex >= frameCount) + break; // 0 frame available, 2 frames needed + // read first frame + read<CHANNELS>(impulse, phaseFraction, in, inputIndex); + inputIndex++; + if (inputIndex >= frameCount) + break; // 0 frame available, 1 frame needed + // read second frame + read<CHANNELS>(impulse, phaseFraction, in, inputIndex); + } } // if done with buffer, save samples @@ -239,80 +268,89 @@ void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount, } } +resample_exit: mImpulse = impulse; mInputIndex = inputIndex; mPhaseFraction = phaseFraction; } template<int CHANNELS> +/*** +* read() +* +* This function reads only one frame from input buffer and writes it in +* state buffer +* +**/ void AudioResamplerSinc::read( - int16_t*& impulse, uint32_t& phaseFraction, - int16_t const* in, size_t inputIndex) + int16_t*& impulse, uint32_t& phaseFraction, + int16_t const* in, size_t inputIndex) { - // read new samples into the ring buffer - while (phaseFraction >> kNumPhaseBits) { - const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits; - impulse += CHANNELS; - phaseFraction -= 1LU<<kNumPhaseBits; - if (impulse >= mRingFull) { - const size_t stateSize = (halfNumCoefs*2)*CHANNELS; - memcpy(mState, mState+stateSize, sizeof(int16_t)*stateSize); - impulse -= stateSize; - } - int16_t* head = impulse + halfNumCoefs*CHANNELS; - head[0] = in[inputIndex*CHANNELS + 0]; - if (CHANNELS == 2) - head[1] = in[inputIndex*CHANNELS + 1]; - } + const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits; + impulse += CHANNELS; + phaseFraction -= 1LU<<kNumPhaseBits; + if (impulse >= mRingFull) { + const size_t stateSize = (halfNumCoefs*2)*CHANNELS; + memcpy(mState, mState+stateSize, sizeof(int16_t)*stateSize); + impulse -= stateSize; + } + int16_t* head = impulse + halfNumCoefs*CHANNELS; + head[0] = in[inputIndex*CHANNELS + 0]; + if (CHANNELS == 2) + head[1] = in[inputIndex*CHANNELS + 1]; } template<int CHANNELS> void AudioResamplerSinc::filterCoefficient( - int32_t& l, int32_t& r, uint32_t phase, int16_t const *samples) -{ - // compute the index of the coefficient on the positive side and - // negative side - uint32_t indexP = (phase & cMask) >> cShift; - uint16_t lerpP = (phase & pMask) >> pShift; - uint32_t indexN = (-phase & cMask) >> cShift; - uint16_t lerpN = (-phase & pMask) >> pShift; - - l = 0; - r = 0; - int32_t const* coefs = mFirCoefs; - int16_t const *sP = samples; - int16_t const *sN = samples+CHANNELS; - for (unsigned int i=0 ; i<halfNumCoefs/4 ; i++) { - interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP); - interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN); - sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits; + int32_t& l, int32_t& r, uint32_t phase, int16_t const *samples) +{ + // compute the index of the coefficient on the positive side and + // negative side + uint32_t indexP = (phase & cMask) >> cShift; + uint16_t lerpP = (phase & pMask) >> pShift; + uint32_t indexN = (-phase & cMask) >> cShift; + uint16_t lerpN = (-phase & pMask) >> pShift; + if ((indexP == 0) && (lerpP == 0)) { + indexN = cMask >> cShift; + lerpN = pMask >> pShift; + } + + l = 0; + r = 0; + int32_t const* coefs = mFirCoefs; + int16_t const *sP = samples; + int16_t const *sN = samples+CHANNELS; + for (unsigned int i=0 ; i<halfNumCoefs/4 ; i++) { interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP); interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN); - sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits; + sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits; interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP); interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN); - sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits; + sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits; interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP); interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN); - sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits; - } + sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits; + interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP); + interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN); + sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits; + } } template<int CHANNELS> void AudioResamplerSinc::interpolate( int32_t& l, int32_t& r, - int32_t const* coefs, int16_t lerp, int16_t const* samples) + int32_t const* coefs, int16_t lerp, int16_t const* samples) { - int32_t c0 = coefs[0]; - int32_t c1 = coefs[1]; - int32_t sinc = mulAdd(lerp, (c1-c0)<<1, c0); - if (CHANNELS == 2) { - uint32_t rl = *reinterpret_cast<uint32_t const*>(samples); - l = mulAddRL(1, rl, sinc, l); - r = mulAddRL(0, rl, sinc, r); - } else { - r = l = mulAdd(samples[0], sinc, l); - } + int32_t c0 = coefs[0]; + int32_t c1 = coefs[1]; + int32_t sinc = mulAdd(lerp, (c1-c0)<<1, c0); + if (CHANNELS == 2) { + uint32_t rl = *reinterpret_cast<uint32_t const*>(samples); + l = mulAddRL(1, rl, sinc, l); + r = mulAddRL(0, rl, sinc, r); + } else { + r = l = mulAdd(samples[0], sinc, l); + } } // ---------------------------------------------------------------------------- diff --git a/libs/audioflinger/AudioResamplerSinc.h b/libs/audioflinger/AudioResamplerSinc.h index 89b9577..e6cb90b 100644 --- a/libs/audioflinger/AudioResamplerSinc.h +++ b/libs/audioflinger/AudioResamplerSinc.h @@ -24,19 +24,20 @@ #include "AudioResampler.h" namespace android { + // ---------------------------------------------------------------------------- class AudioResamplerSinc : public AudioResampler { public: - AudioResamplerSinc(int bitDepth, int inChannelCount, int32_t sampleRate); + AudioResamplerSinc(int bitDepth, int inChannelCount, int32_t sampleRate); + + ~AudioResamplerSinc(); - ~AudioResamplerSinc(); - virtual void resample(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider); private: void init(); - + template<int CHANNELS> void resample(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider); @@ -52,12 +53,12 @@ private: template<int CHANNELS> inline void read(int16_t*& impulse, uint32_t& phaseFraction, - int16_t const* in, size_t inputIndex); + int16_t const* in, size_t inputIndex); int16_t *mState; int16_t *mImpulse; int16_t *mRingFull; - + int32_t const * mFirCoefs; static const int32_t mFirCoefsDown[]; static const int32_t mFirCoefsUp[]; @@ -67,15 +68,15 @@ private: static const int32_t RESAMPLE_FIR_LERP_INT_BITS = 4; // we have 16 coefs samples per zero-crossing - static const int coefsBits = RESAMPLE_FIR_LERP_INT_BITS; - static const int cShift = kNumPhaseBits - coefsBits; - static const uint32_t cMask = ((1<<coefsBits)-1) << cShift; + static const int coefsBits = RESAMPLE_FIR_LERP_INT_BITS; // 4 + static const int cShift = kNumPhaseBits - coefsBits; // 26 + static const uint32_t cMask = ((1<<coefsBits)-1) << cShift; // 0xf<<26 = 3c00 0000 // and we use 15 bits to interpolate between these samples // this cannot change because the mul below rely on it. static const int pLerpBits = 15; - static const int pShift = kNumPhaseBits - coefsBits - pLerpBits; - static const uint32_t pMask = ((1<<pLerpBits)-1) << pShift; + static const int pShift = kNumPhaseBits - coefsBits - pLerpBits; // 11 + static const uint32_t pMask = ((1<<pLerpBits)-1) << pShift; // 0x7fff << 11 // number of zero-crossing on each side static const unsigned int halfNumCoefs = RESAMPLE_FIR_NUM_COEF; |