Initial Contribution
diff --git a/libs/audioflinger/Android.mk b/libs/audioflinger/Android.mk
new file mode 100644
index 0000000..a9cb3037
--- /dev/null
+++ b/libs/audioflinger/Android.mk
@@ -0,0 +1,53 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ AudioHardwareGeneric.cpp \
+ AudioHardwareStub.cpp \
+ AudioDumpInterface.cpp \
+ AudioHardwareInterface.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libmedia \
+ libhardware
+
+ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
+ LOCAL_CFLAGS += -DGENERIC_AUDIO
+endif
+
+LOCAL_MODULE:= libaudiointerface
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ AudioFlinger.cpp \
+ AudioMixer.cpp.arm \
+ AudioResampler.cpp.arm \
+ AudioResamplerSinc.cpp.arm \
+ AudioResamplerCubic.cpp.arm
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libmedia \
+ libhardware
+
+ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
+ LOCAL_STATIC_LIBRARIES += libaudiointerface
+else
+ LOCAL_SHARED_LIBRARIES += libaudio
+endif
+
+LOCAL_MODULE:= libaudioflinger
+
+ifeq ($(TARGET_ARCH),arm) # not simulator
+ LOCAL_CFLAGS += -DWITH_BLUETOOTH
+ LOCAL_C_INCLUDES += $(call include-path-for, bluez-libs)
+endif
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/audioflinger/AudioBufferProvider.h b/libs/audioflinger/AudioBufferProvider.h
new file mode 100644
index 0000000..1a467c7
--- /dev/null
+++ b/libs/audioflinger/AudioBufferProvider.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_BUFFER_PROVIDER_H
+#define ANDROID_AUDIO_BUFFER_PROVIDER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class AudioBufferProvider
+{
+public:
+
+ struct Buffer {
+ union {
+ void* raw;
+ short* i16;
+ int8_t* i8;
+ };
+ size_t frameCount;
+ };
+
+ virtual status_t getNextBuffer(Buffer* buffer) = 0;
+ virtual void releaseBuffer(Buffer* buffer) = 0;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_AUDIO_BUFFER_PROVIDER_H
diff --git a/libs/audioflinger/AudioDumpInterface.cpp b/libs/audioflinger/AudioDumpInterface.cpp
new file mode 100644
index 0000000..5ff2f18
--- /dev/null
+++ b/libs/audioflinger/AudioDumpInterface.cpp
@@ -0,0 +1,94 @@
+/* //device/servers/AudioFlinger/AudioDumpInterface.cpp
+**
+** 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
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "AudioFlingerDump"
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "AudioDumpInterface.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+AudioDumpInterface::AudioDumpInterface(AudioHardwareInterface* hw)
+{
+ if(hw == 0) {
+ LOGE("Dump construct hw = 0");
+ }
+ mFinalInterface = hw;
+ mStreamOut = 0;
+}
+
+
+status_t AudioDumpInterface::standby()
+{
+ if(mStreamOut) mStreamOut->Close();
+ return mFinalInterface->standby();
+}
+
+
+AudioStreamOut* AudioDumpInterface::openOutputStream(
+ int format, int channelCount, uint32_t sampleRate)
+{
+ AudioStreamOut* outFinal = mFinalInterface->openOutputStream(format, channelCount, sampleRate);
+
+ if(outFinal) {
+ mStreamOut = new AudioStreamOutDump(outFinal);
+ return mStreamOut;
+ } else {
+ LOGE("Dump outFinal=0");
+ return 0;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+AudioStreamOutDump::AudioStreamOutDump( AudioStreamOut* finalStream)
+{
+ mFinalStream = finalStream;
+ mOutFile = 0;
+}
+
+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) {
+ fwrite(buffer, bytes, 1, mOutFile);
+ }
+ return ret;
+}
+
+void AudioStreamOutDump::Close(void)
+{
+ if(mOutFile) {
+ fclose(mOutFile);
+ mOutFile = 0;
+ }
+}
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h
new file mode 100644
index 0000000..732b97d
--- /dev/null
+++ b/libs/audioflinger/AudioDumpInterface.h
@@ -0,0 +1,101 @@
+/* //device/servers/AudioFlinger/AudioDumpInterface.h
+**
+** 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
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_AUDIO_DUMP_INTERFACE_H
+#define ANDROID_AUDIO_DUMP_INTERFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <hardware/AudioHardwareInterface.h>
+
+namespace android {
+
+#define FLINGER_DUMP_NAME "/tmp/FlingerOut.pcm" // name of file used for dump
+
+class AudioStreamOutDump : public AudioStreamOut {
+public:
+ AudioStreamOutDump( AudioStreamOut* FinalStream);
+ 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 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
+};
+
+
+class AudioDumpInterface : public AudioHardwareInterface
+{
+
+public:
+ AudioDumpInterface(AudioHardwareInterface* hw);
+ virtual status_t standby();
+ virtual AudioStreamOut* openOutputStream(
+ int format=0,
+ int channelCount=0,
+ uint32_t sampleRate=0);
+
+ virtual ~AudioDumpInterface()
+ {delete mFinalInterface;}
+ virtual status_t initCheck()
+ {return mFinalInterface->initCheck();}
+ virtual status_t setVoiceVolume(float volume)
+ {return mFinalInterface->setVoiceVolume(volume);}
+ 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);}
+ virtual status_t getMicMute(bool* state)
+ {return mFinalInterface->getMicMute(state);}
+
+ 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 status_t dump(int fd, const Vector<String16>& args) { return mFinalInterface->dumpState(fd, args); }
+
+protected:
+ virtual status_t doRouting() {return 0;}
+
+ AudioHardwareInterface *mFinalInterface;
+ AudioStreamOutDump *mStreamOut;
+
+};
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_DUMP_INTERFACE_H
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
new file mode 100644
index 0000000..fb21629
--- /dev/null
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -0,0 +1,1450 @@
+/* //device/include/server/AudioFlinger/AudioFlinger.cpp
+**
+** 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
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+
+#define LOG_TAG "AudioFlinger"
+//#define LOG_NDEBUG 0
+
+#include <math.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <utils/IServiceManager.h>
+#include <utils/Log.h>
+#include <utils/Parcel.h>
+#include <utils/IPCThreadState.h>
+#include <utils/String16.h>
+#include <utils/threads.h>
+
+#include <media/AudioTrack.h>
+#include <media/AudioRecord.h>
+
+#include <private/media/AudioTrackShared.h>
+
+#include <hardware/AudioHardwareInterface.h>
+
+#include "AudioMixer.h"
+#include "AudioFlinger.h"
+
+namespace android {
+
+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;
+
+// retry counts for buffer fill timeout
+// 50 * ~20msecs = 1 second
+static const int8_t kMaxTrackRetries = 50;
+static const int8_t kMaxTrackStartupRetries = 50;
+
+#define AUDIOFLINGER_SECURITY_ENABLED 1
+
+// ----------------------------------------------------------------------------
+
+static bool recordingAllowed() {
+#ifndef HAVE_ANDROID_OS
+ return true;
+#endif
+#if AUDIOFLINGER_SECURITY_ENABLED
+ if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
+ bool ok = checkCallingPermission(String16("android.permission.RECORD_AUDIO"));
+ if (!ok) LOGE("Request requires android.permission.RECORD_AUDIO");
+ return ok;
+#else
+ if (!checkCallingPermission(String16("android.permission.RECORD_AUDIO")))
+ LOGW("WARNING: Need to add android.permission.RECORD_AUDIO to manifest");
+ return true;
+#endif
+}
+
+static bool settingsAllowed() {
+#ifndef HAVE_ANDROID_OS
+ return true;
+#endif
+#if AUDIOFLINGER_SECURITY_ENABLED
+ if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
+ bool ok = checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS"));
+ if (!ok) LOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS");
+ return ok;
+#else
+ if (!checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS")))
+ LOGW("WARNING: Need to add android.permission.MODIFY_AUDIO_SETTINGS to manifest");
+ return true;
+#endif
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::AudioFlinger()
+ : BnAudioFlinger(), Thread(false),
+ mMasterVolume(0), mMasterMute(true),
+ mAudioMixer(0), mAudioHardware(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)
+{
+ mHardwareStatus = AUDIO_HW_IDLE;
+ mAudioHardware = AudioHardwareInterface::create();
+ mHardwareStatus = AUDIO_HW_INIT;
+ 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);
+ 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);
+ // FIXME - this should come from settings
+ setMasterVolume(1.0f);
+ setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
+ setRouting(AudioSystem::MODE_RINGTONE, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
+ setRouting(AudioSystem::MODE_IN_CALL, AudioSystem::ROUTE_EARPIECE, AudioSystem::ROUTE_ALL);
+ setMode(AudioSystem::MODE_NORMAL);
+ mMasterMute = false;
+ } else {
+ LOGE("Failed to initialize output stream");
+ }
+ } else {
+ LOGE("Couldn't even initialize the stubbed audio hardware!");
+ }
+}
+
+AudioFlinger::~AudioFlinger()
+{
+ delete mOutput;
+ delete mAudioHardware;
+ delete [] mMixBuffer;
+ delete mAudioMixer;
+ mAudioRecordThread.clear();
+}
+
+status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ result.append("Clients:\n");
+ for (size_t i = 0; i < mClients.size(); ++i) {
+ wp<Client> wClient = mClients.valueAt(i);
+ if (wClient != 0) {
+ sp<Client> client = wClient.promote();
+ if (client != 0) {
+ snprintf(buffer, SIZE, " pid: %d\n", client->pid());
+ result.append(buffer);
+ }
+ }
+ }
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::dumpTracks(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ result.append("Tracks:\n");
+ result.append(" Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
+ for (size_t i = 0; i < mTracks.size(); ++i) {
+ wp<Track> wTrack = mTracks[i];
+ if (wTrack != 0) {
+ sp<Track> track = wTrack.promote();
+ if (track != 0) {
+ track->dump(buffer, SIZE);
+ result.append(buffer);
+ }
+ }
+ }
+
+ result.append("Active Tracks:\n");
+ result.append(" Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
+ for (size_t i = 0; i < mActiveTracks.size(); ++i) {
+ wp<Track> wTrack = mTracks[i];
+ if (wTrack != 0) {
+ sp<Track> track = wTrack.promote();
+ if (track != 0) {
+ track->dump(buffer, SIZE);
+ result.append(buffer);
+ }
+ }
+ }
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+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());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
+ result.append(buffer);
+ snprintf(buffer, SIZE, "total writes: %d\n", mNumWrites);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "delayed writes: %d\n", mNumDelayedWrites);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "blocked in write: %d\n", mInWrite);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "standby: %d\n", mStandby);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "Hardware status: %d\n", mHardwareStatus);
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, SIZE, "Permission Denial: "
+ "can't dump AudioFlinger from pid=%d, uid=%d\n",
+ IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid());
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
+{
+ if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+ dumpPermissionDenial(fd, args);
+ } else {
+ AutoMutex lock(&mLock);
+
+ dumpClients(fd, args);
+ dumpTracks(fd, args);
+ dumpInternals(fd, args);
+ if (mAudioHardware) {
+ mAudioHardware->dumpState(fd, args);
+ }
+ }
+ return NO_ERROR;
+}
+
+// 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;
+ nsecs_t standbyTime = systemTime();
+
+ do {
+ enabledTracks = 0;
+ { // scope for the lock
+ Mutex::Autolock _l(mLock);
+ const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
+
+ // put audio hardware into standby after short delay
+ if UNLIKELY(!activeTracks.size() && systemTime() > standbyTime) {
+ // wait until we have something to do...
+ LOGV("Audio hardware entering standby\n");
+ mHardwareStatus = AUDIO_HW_STANDBY;
+ if (!mStandby) {
+ mAudioHardware->standby();
+ mStandby = true;
+ }
+ mHardwareStatus = AUDIO_HW_IDLE;
+ // we're about to wait, flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
+ mWaitWorkCV.wait(mLock);
+ LOGV("Audio hardware exiting standby\n");
+ standbyTime = systemTime() + kStandbyTimeInNsecs;
+ continue;
+ }
+
+ // find out which tracks need to be processed
+ size_t count = activeTracks.size();
+ for (size_t i=0 ; i<count ; i++) {
+ sp<Track> t = activeTracks[i].promote();
+ if (t == 0) continue;
+
+ 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()) &&
+ !track->isPaused())
+ {
+ //LOGD("u=%08x, s=%08x [OK]", u, s);
+
+ // compute volume for this track
+ int16_t left, right;
+ if (track->isMuted() || mMasterMute || track->isPausing()) {
+ left = right = 0;
+ if (track->isPausing()) {
+ LOGV("paused(%d)", track->name());
+ track->setPaused();
+ }
+ } else {
+ float typeVolume = mStreamTypes[track->type()].volume;
+ float v = mMasterVolume * typeVolume;
+ float v_clamped = v * cblk->volume[0];
+ if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+ left = int16_t(v_clamped);
+ v_clamped = v * cblk->volume[1];
+ if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+ right = int16_t(v_clamped);
+ }
+
+ // XXX: these things DON'T need to be done each time
+ AudioMixer& mixer(audioMixer());
+ mixer.setBufferProvider(track);
+ mixer.enable(AudioMixer::MIXING);
+
+ int param;
+ if ( track->mFillingUpStatus == Track::FS_FILLED) {
+ // no ramp for the first volume setting
+ track->mFillingUpStatus = Track::FS_ACTIVE;
+ if (track->mState == TrackBase::RESUMING) {
+ track->mState = TrackBase::ACTIVE;
+ param = AudioMixer::RAMP_VOLUME;
+ } else {
+ param = AudioMixer::VOLUME;
+ }
+ } else {
+ param = AudioMixer::RAMP_VOLUME;
+ }
+ mixer.setParameter(param, AudioMixer::VOLUME0, left);
+ mixer.setParameter(param, AudioMixer::VOLUME1, right);
+ mixer.setParameter(
+ AudioMixer::TRACK,
+ AudioMixer::FORMAT, track->format());
+ mixer.setParameter(
+ AudioMixer::TRACK,
+ AudioMixer::CHANNEL_COUNT, track->channelCount());
+ mixer.setParameter(
+ AudioMixer::RESAMPLE,
+ AudioMixer::SAMPLE_RATE,
+ int(cblk->sampleRate));
+
+ // reset retry count
+ track->mRetryCount = kMaxTrackRetries;
+ enabledTracks++;
+ } else {
+ //LOGD("u=%08x, s=%08x [NOT READY]", u, s);
+ if (track->isStopped()) {
+ track->mFillingUpStatus = Track::FS_FILLING;
+ track->mFlags = 0;
+ }
+ if (track->isTerminated() || track->isStopped() || track->isPaused()) {
+ // We have consumed all the buffers of this track.
+ // Remove it from the list of active tracks.
+ LOGV("remove(%d) from active list", track->name());
+ tracksToRemove.add(track);
+ } else {
+ // No buffers for this track. Give it a few chances to
+ // fill a buffer, then remove it from active list.
+ if (--(track->mRetryCount) <= 0) {
+ LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
+ tracksToRemove.add(track);
+ }
+ }
+ // LOGV("disable(%d)", track->name());
+ audioMixer().disable(AudioMixer::MIXING);
+ }
+ }
+
+ // remove all the tracks that need to be...
+ count = tracksToRemove.size();
+ if (UNLIKELY(count)) {
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<Track>& track = tracksToRemove[i];
+ mActiveTracks.remove(track);
+ if (track->isTerminated()) {
+ mTracks.remove(track);
+ audioMixer().deleteTrackName(track->mName);
+ }
+ }
+ }
+ }
+
+ if (LIKELY(enabledTracks)) {
+ // mix buffers...
+ audioMixer().process(curBuf);
+
+ // output audio to hardware
+ mLastWriteTime = systemTime();
+ mInWrite = true;
+ mOutput->write(curBuf, mixBufferSize);
+ mNumWrites++;
+ mInWrite = false;
+ mStandby = false;
+ nsecs_t temp = systemTime();
+ standbyTime = temp + kStandbyTimeInNsecs;
+ nsecs_t delta = temp - mLastWriteTime;
+ if (delta > maxPeriod) {
+ LOGW("write blocked for %llu msecs", ns2ms(delta));
+ mNumDelayedWrites++;
+ }
+ sleepTime = kBufferRecoveryInUsecs;
+ } else {
+ // There was nothing to mix this round, which means all
+ // active tracks were late. Sleep a little bit to give
+ // them another chance. If we're too late, the audio
+ // hardware will zero-fill for us.
+ LOGV("no buffers - usleep(%lu)", sleepTime);
+ usleep(sleepTime);
+ if (sleepTime < kMaxBufferRecoveryInUsecs) {
+ sleepTime += kBufferRecoveryInUsecs;
+ }
+ }
+
+ // finally let go of all our tracks, without the lock held
+ // since we can't guarantee the destructors won't acquire that
+ // same lock.
+ tracksToRemove.clear();
+ } while (true);
+
+ return false;
+}
+
+status_t AudioFlinger::readyToRun()
+{
+ if (mSampleRate == 0) {
+ LOGE("No working audio driver found.");
+ return NO_INIT;
+ }
+ LOGI("AudioFlinger's main thread ready to run.");
+ return NO_ERROR;
+}
+
+void AudioFlinger::onFirstRef()
+{
+ run("AudioFlinger", ANDROID_PRIORITY_URGENT_AUDIO);
+}
+
+// IAudioFlinger interface
+sp<IAudioTrack> AudioFlinger::createTrack(
+ pid_t pid,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ uint32_t flags)
+{
+ if (streamType >= AudioTrack::NUM_STREAM_TYPES) {
+ LOGE("invalid stream type");
+ return NULL;
+ }
+
+ if (sampleRate > MAX_SAMPLE_RATE) {
+ LOGE("Sample rate out of range: %d", sampleRate);
+ return NULL;
+ }
+
+ sp<Track> track;
+ sp<TrackHandle> trackHandle;
+ Mutex::Autolock _l(mLock);
+
+ if (mSampleRate == 0) {
+ LOGE("Audio driver not initialized.");
+ return trackHandle;
+ }
+
+ sp<Client> client;
+ wp<Client> wclient = mClients.valueFor(pid);
+
+ if (wclient != NULL) {
+ client = wclient.promote();
+ } else {
+ client = new Client(this, pid);
+ mClients.add(pid, client);
+ }
+
+ // 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);
+ return trackHandle;
+}
+
+uint32_t AudioFlinger::sampleRate() const
+{
+ return mSampleRate;
+}
+
+int AudioFlinger::channelCount() const
+{
+ return mChannelCount;
+}
+
+int AudioFlinger::format() const
+{
+ return mFormat;
+}
+
+size_t AudioFlinger::frameCount() const
+{
+ return mFrameCount;
+}
+
+status_t AudioFlinger::setMasterVolume(float value)
+{
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+
+ // when hw supports master volume, don't scale in sw mixer
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+ if (mAudioHardware->setMasterVolume(value) == NO_ERROR) {
+ mMasterVolume = 1.0f;
+ }
+ else {
+ mMasterVolume = value;
+ }
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::setRouting(int mode, uint32_t routes, uint32_t mask)
+{
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+ if ((mode < AudioSystem::MODE_CURRENT) || (mode >= AudioSystem::NUM_MODES)) {
+ LOGW("Illegal value: setRouting(%d, %u, %u)", mode, routes, mask);
+ return BAD_VALUE;
+ }
+
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_HW_GET_ROUTING;
+ uint32_t r;
+ uint32_t err = mAudioHardware->getRouting(mode, &r);
+ if (err == NO_ERROR) {
+ r = (r & ~mask) | (routes & mask);
+ mHardwareStatus = AUDIO_HW_SET_ROUTING;
+ err = mAudioHardware->setRouting(mode, r);
+ }
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return err;
+}
+
+uint32_t AudioFlinger::getRouting(int mode) const
+{
+ uint32_t routes = 0;
+ if ((mode >= AudioSystem::MODE_CURRENT) && (mode < AudioSystem::NUM_MODES)) {
+ mHardwareStatus = AUDIO_HW_GET_ROUTING;
+ mAudioHardware->getRouting(mode, &routes);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ } else {
+ LOGW("Illegal value: getRouting(%d)", mode);
+ }
+ return routes;
+}
+
+status_t AudioFlinger::setMode(int mode)
+{
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+ if ((mode < 0) || (mode >= AudioSystem::NUM_MODES)) {
+ LOGW("Illegal value: setMode(%d)", mode);
+ return BAD_VALUE;
+ }
+
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_HW_SET_MODE;
+ status_t ret = mAudioHardware->setMode(mode);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return ret;
+}
+
+int AudioFlinger::getMode() const
+{
+ int mode = AudioSystem::MODE_INVALID;
+ mHardwareStatus = AUDIO_HW_SET_MODE;
+ mAudioHardware->getMode(&mode);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return mode;
+}
+
+status_t AudioFlinger::setMicMute(bool state)
+{
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_HW_SET_MIC_MUTE;
+ status_t ret = mAudioHardware->setMicMute(state);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return ret;
+}
+
+bool AudioFlinger::getMicMute() const
+{
+ bool state = AudioSystem::MODE_INVALID;
+ mHardwareStatus = AUDIO_HW_GET_MIC_MUTE;
+ mAudioHardware->getMicMute(&state);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return state;
+}
+
+status_t AudioFlinger::setMasterMute(bool muted)
+{
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+
+ mMasterMute = muted;
+ return NO_ERROR;
+}
+
+float AudioFlinger::masterVolume() const
+{
+ return mMasterVolume;
+}
+
+bool AudioFlinger::masterMute() const
+{
+ return mMasterMute;
+}
+
+status_t AudioFlinger::setStreamVolume(int stream, float value)
+{
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+
+ 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) {
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_SET_VOICE_VOLUME;
+ ret = mAudioHardware->setVoiceVolume(value);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ }
+ return ret;
+}
+
+status_t AudioFlinger::setStreamMute(int stream, bool muted)
+{
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+
+ if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+ return BAD_VALUE;
+ }
+ mStreamTypes[stream].mute = muted;
+ return NO_ERROR;
+}
+
+float AudioFlinger::streamVolume(int stream) const
+{
+ if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+ return 0.0f;
+ }
+ return mStreamTypes[stream].volume;
+}
+
+bool AudioFlinger::streamMute(int stream) const
+{
+ if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+ return true;
+ }
+ return mStreamTypes[stream].mute;
+}
+
+bool AudioFlinger::isMusicActive() const
+{
+ size_t count = mActiveTracks.size();
+ for (size_t i = 0 ; i < count ; ++i) {
+ sp<Track> t = mActiveTracks[i].promote();
+ if (t == 0) continue;
+ Track* const track = t.get();
+ if (t->mStreamType == AudioTrack::MUSIC)
+ return true;
+ }
+ return false;
+}
+
+status_t AudioFlinger::setParameter(const char* key, const char* value)
+{
+ status_t result;
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_SET_PARAMETER;
+ result = mAudioHardware->setParameter(key, value);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return result;
+}
+
+void AudioFlinger::removeClient(pid_t pid)
+{
+ Mutex::Autolock _l(mLock);
+ mClients.removeItem(pid);
+}
+
+status_t AudioFlinger::addTrack(const sp<Track>& track)
+{
+ Mutex::Autolock _l(mLock);
+
+ // here the track could be either new, or restarted
+ // in both cases "unstop" the track
+ if (track->isPaused()) {
+ track->mState = TrackBase::RESUMING;
+ LOGV("PAUSED => RESUMING (%d)", track->name());
+ } else {
+ track->mState = TrackBase::ACTIVE;
+ LOGV("? => ACTIVE (%d)", track->name());
+ }
+ // set retry count for buffer fill
+ track->mRetryCount = kMaxTrackStartupRetries;
+ LOGV("mWaitWorkCV.broadcast");
+ mWaitWorkCV.broadcast();
+
+ if (mActiveTracks.indexOf(track) < 0) {
+ // the track is newly added, make sure it fills up all its
+ // buffers before playing. This is to ensure the client will
+ // effectively get the latency it requested.
+ track->mFillingUpStatus = Track::FS_FILLING;
+ mActiveTracks.add(track);
+ return NO_ERROR;
+ }
+ return ALREADY_EXISTS;
+}
+
+void AudioFlinger::removeTrack(wp<Track> track, int name)
+{
+ Mutex::Autolock _l(mLock);
+ sp<Track> t = track.promote();
+ if (t!=NULL && (t->mState <= TrackBase::STOPPED)) {
+ remove_track_l(track, name);
+ }
+}
+
+void AudioFlinger::remove_track_l(wp<Track> track, int name)
+{
+ sp<Track> t = track.promote();
+ if (t!=NULL) {
+ t->reset();
+ }
+ audioMixer().deleteTrackName(name);
+ mActiveTracks.remove(track);
+ mWaitWorkCV.broadcast();
+}
+
+void AudioFlinger::destroyTrack(const sp<Track>& track)
+{
+ // NOTE: We're acquiring a strong reference on the track before
+ // acquiring the lock, this is to make sure removing it from
+ // mTracks won't cause the destructor to be called while the lock is
+ // held (note that technically, 'track' could be a reference to an item
+ // in mTracks, which is why we need to do this).
+ sp<Track> keep(track);
+ Mutex::Autolock _l(mLock);
+ track->mState = TrackBase::TERMINATED;
+ if (mActiveTracks.indexOf(track) < 0) {
+ LOGV("remove track (%d) and delete from mixer", track->name());
+ mTracks.remove(track);
+ audioMixer().deleteTrackName(keep->name());
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
+ : RefBase(),
+ mAudioFlinger(audioFlinger),
+ mMemoryDealer(new MemoryDealer(1024*1024)),
+ mPid(pid)
+{
+ // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
+}
+
+AudioFlinger::Client::~Client()
+{
+ mAudioFlinger->removeClient(mPid);
+}
+
+const sp<MemoryDealer>& AudioFlinger::Client::heap() const
+{
+ return mMemoryDealer;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::TrackBase::TrackBase(
+ const sp<AudioFlinger>& audioFlinger,
+ const sp<Client>& client,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ int bufferSize)
+ : RefBase(),
+ mAudioFlinger(audioFlinger),
+ mClient(client),
+ mStreamType(streamType),
+ mFormat(format),
+ mChannelCount(channelCount),
+ mBufferCount(bufferCount),
+ mFlags(0),
+ mBufferSize(bufferSize),
+ mState(IDLE),
+ mClientTid(-1)
+{
+ mName = audioFlinger->audioMixer().getTrackName();
+ if (mName < 0) {
+ LOGE("no more track names availlable");
+ return;
+ }
+
+ // LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
+ size_t size = sizeof(audio_track_cblk_t) + bufferCount * 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->sampleRate = sampleRate;
+ mBuffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+ memset(mBuffers, 0, bufferCount * bufferSize);
+ }
+ } else {
+ LOGE("not enough memory for AudioTrack size=%u", size);
+ client->heap()->dump("AudioTrack");
+ return;
+ }
+}
+
+AudioFlinger::TrackBase::~TrackBase()
+{
+ mCblk->~audio_track_cblk_t(); // destroy our shared-structure.
+ mCblkMemory.clear(); // and free the shared memory
+ mClient.clear();
+}
+
+void AudioFlinger::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
+{
+ buffer->raw = 0;
+ buffer->frameCount = 0;
+ step();
+}
+
+bool AudioFlinger::TrackBase::step() {
+ bool result;
+ audio_track_cblk_t* cblk = this->cblk();
+
+ result = cblk->stepServer(bufferCount());
+ if (!result) {
+ LOGV("stepServer failed acquiring cblk mutex");
+ mFlags |= STEPSERVER_FAILED;
+ }
+ return result;
+}
+
+void AudioFlinger::TrackBase::reset() {
+ audio_track_cblk_t* cblk = this->cblk();
+
+ cblk->user = 0;
+ cblk->server = 0;
+ mFlags = 0;
+}
+
+sp<IMemory> AudioFlinger::TrackBase::getCblk() const
+{
+ return mCblkMemory;
+}
+
+int AudioFlinger::TrackBase::sampleRate() const {
+ return mCblk->sampleRate;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::Track::Track(
+ const sp<AudioFlinger>& audioFlinger,
+ const sp<Client>& client,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ int bufferSize)
+ : TrackBase(audioFlinger, client, streamType, sampleRate, format, channelCount, bufferCount, bufferSize)
+{
+ mVolume[0] = 1.0f;
+ mVolume[1] = 1.0f;
+ mMute = false;
+}
+
+AudioFlinger::Track::~Track()
+{
+ wp<Track> weak(this); // never create a strong ref from the dtor
+ mState = TERMINATED;
+ mAudioFlinger->removeTrack(weak, mName);
+}
+
+void AudioFlinger::Track::destroy()
+{
+ mAudioFlinger->destroyTrack(this);
+}
+
+void AudioFlinger::Track::dump(char* buffer, size_t size)
+{
+ snprintf(buffer, size, " %5d %5d %3u %3u %3u %3u %1d %1d %1d %5u %5u %5u %04x %04x\n",
+ mName - AudioMixer::TRACK0,
+ mClient->pid(),
+ mStreamType,
+ mFormat,
+ mChannelCount,
+ mBufferCount,
+ mState,
+ mMute,
+ mFillingUpStatus,
+ mCblk->sampleRate,
+ mCblk->volume[0],
+ mCblk->volume[1],
+ mCblk->server,
+ mCblk->user);
+}
+
+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
+ 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;
+ }
+getNextBuffer_exit:
+ buffer->raw = 0;
+ buffer->frameCount = 0;
+ return NOT_ENOUGH_DATA;
+}
+
+bool AudioFlinger::Track::isReady(uint32_t u, int32_t s) 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) {
+ mFillingUpStatus = FS_FILLED;
+ return true;
+ }
+ return false;
+}
+
+status_t AudioFlinger::Track::start()
+{
+ LOGV("start(%d)", mName);
+ mAudioFlinger->addTrack(this);
+ return NO_ERROR;
+}
+
+void AudioFlinger::Track::stop()
+{
+ LOGV("stop(%d)", mName);
+ Mutex::Autolock _l(mAudioFlinger->mLock);
+ if (mState > STOPPED) {
+ mState = STOPPED;
+ // If the track is not active (PAUSED and buffers full), flush buffers
+ if (mAudioFlinger->mActiveTracks.indexOf(this) < 0) {
+ reset();
+ }
+ LOGV("(> STOPPED) => STOPPED (%d)", mName);
+ }
+}
+
+void AudioFlinger::Track::pause()
+{
+ LOGV("pause(%d)", mName);
+ Mutex::Autolock _l(mAudioFlinger->mLock);
+ if (mState == ACTIVE || mState == RESUMING) {
+ mState = PAUSING;
+ LOGV("ACTIVE/RESUMING => PAUSING (%d)", mName);
+ }
+}
+
+void AudioFlinger::Track::flush()
+{
+ LOGV("flush(%d)", mName);
+ Mutex::Autolock _l(mAudioFlinger->mLock);
+ if (mState != STOPPED && mState != PAUSED && mState != PAUSING) {
+ return;
+ }
+ // No point remaining in PAUSED state after a flush => go to
+ // STOPPED state
+ mState = STOPPED;
+
+ // 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!
+ reset();
+}
+
+void AudioFlinger::Track::reset()
+{
+ TrackBase::reset();
+ mFillingUpStatus = FS_FILLING;
+}
+
+void AudioFlinger::Track::mute(bool muted)
+{
+ mMute = muted;
+}
+
+void AudioFlinger::Track::setVolume(float left, float right)
+{
+ mVolume[0] = left;
+ mVolume[1] = right;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::Track>& track)
+ : BnAudioTrack(),
+ mTrack(track)
+{
+}
+
+AudioFlinger::TrackHandle::~TrackHandle() {
+ // just stop the track on deletion, associated resources
+ // will be freed from the main thread once all pending buffers have
+ // been played. Unless it's not in the active track list, in which
+ // case we free everything now...
+ mTrack->destroy();
+}
+
+status_t AudioFlinger::TrackHandle::start() {
+ return mTrack->start();
+}
+
+void AudioFlinger::TrackHandle::stop() {
+ mTrack->stop();
+}
+
+void AudioFlinger::TrackHandle::flush() {
+ mTrack->flush();
+}
+
+void AudioFlinger::TrackHandle::mute(bool e) {
+ mTrack->mute(e);
+}
+
+void AudioFlinger::TrackHandle::pause() {
+ mTrack->pause();
+}
+
+void AudioFlinger::TrackHandle::setVolume(float left, float right) {
+ mTrack->setVolume(left, right);
+}
+
+sp<IMemory> AudioFlinger::TrackHandle::getCblk() const {
+ return mTrack->getCblk();
+}
+
+status_t AudioFlinger::TrackHandle::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ return BnAudioTrack::onTransact(code, data, reply, flags);
+}
+
+// ----------------------------------------------------------------------------
+
+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)
+{
+ sp<AudioRecordThread> thread;
+ sp<RecordTrack> recordTrack;
+ sp<RecordHandle> recordHandle;
+ sp<Client> client;
+ wp<Client> wclient;
+ AudioStreamIn* input = 0;
+
+ // check calling permissions
+ if (!recordingAllowed()) {
+ goto Exit;
+ }
+
+ if (uint32_t(streamType) >= AudioRecord::NUM_STREAM_TYPES) {
+ LOGE("invalid stream type");
+ goto Exit;
+ }
+
+ if (sampleRate > MAX_SAMPLE_RATE) {
+ LOGE("Sample rate out of range");
+ goto Exit;
+ }
+
+ if (mSampleRate == 0) {
+ LOGE("Audio driver not initialized");
+ 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();
+ goto Exit;
+ }
+
+ // add client to list
+ {
+ Mutex::Autolock _l(mLock);
+ wclient = mClients.valueFor(pid);
+ if (wclient != NULL) {
+ client = wclient.promote();
+ } else {
+ client = new Client(this, pid);
+ mClients.add(pid, client);
+ }
+ }
+
+ // 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);
+
+ // return to handle to client
+ recordHandle = new RecordHandle(recordTrack);
+
+Exit:
+ return recordHandle;
+}
+
+status_t AudioFlinger::startRecord() {
+ sp<AudioRecordThread> t = audioRecordThread();
+ if (t == 0) return NO_INIT;
+ return t->start();
+}
+
+void AudioFlinger::stopRecord() {
+ sp<AudioRecordThread> t = audioRecordThread();
+ if (t != 0) t->stop();
+}
+
+void AudioFlinger::exitRecord()
+{
+ sp<AudioRecordThread> t = audioRecordThread();
+ if (t != 0) t->exit();
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::RecordTrack::RecordTrack(
+ const sp<AudioFlinger>& audioFlinger,
+ const sp<Client>& client,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ int bufferSize)
+ : TrackBase(audioFlinger, client, streamType, sampleRate, format,
+ channelCount, bufferCount, bufferSize),
+ mOverflow(false)
+{
+}
+
+AudioFlinger::RecordTrack::~RecordTrack()
+{
+ mAudioFlinger->audioMixer().deleteTrackName(mName);
+ mAudioFlinger->exitRecord();
+}
+
+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;
+ }
+
+ if (LIKELY(s_seq == u_seq || s_buf != u_buf)) {
+ buffer->raw = getBuffer(s_buf);
+ buffer->frameCount = mAudioFlinger->frameCount();
+ return NO_ERROR;
+ }
+
+getNextBuffer_exit:
+ buffer->raw = 0;
+ buffer->frameCount = 0;
+ return NOT_ENOUGH_DATA;
+}
+
+status_t AudioFlinger::RecordTrack::start()
+{
+ return mAudioFlinger->startRecord();
+}
+
+void AudioFlinger::RecordTrack::stop()
+{
+ mAudioFlinger->stopRecord();
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::RecordTrack>& recordTrack)
+ : BnAudioRecord(),
+ mRecordTrack(recordTrack)
+{
+}
+
+AudioFlinger::RecordHandle::~RecordHandle() {}
+
+status_t AudioFlinger::RecordHandle::start() {
+ LOGV("RecordHandle::start()");
+ return mRecordTrack->start();
+}
+
+void AudioFlinger::RecordHandle::stop() {
+ LOGV("RecordHandle::stop()");
+ mRecordTrack->stop();
+}
+
+sp<IMemory> AudioFlinger::RecordHandle::getCblk() const {
+ return mRecordTrack->getCblk();
+}
+
+status_t AudioFlinger::RecordHandle::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ return BnAudioRecord::onTransact(code, data, reply, flags);
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::AudioRecordThread::AudioRecordThread(const sp<AudioFlinger>& audioFlinger) :
+ mAudioFlinger(audioFlinger),
+ mRecordTrack(0),
+ mInput(0),
+ mActive(false)
+{
+}
+
+AudioFlinger::AudioRecordThread::~AudioRecordThread()
+{
+}
+
+bool AudioFlinger::AudioRecordThread::threadLoop()
+{
+ LOGV("AudioRecordThread: start record loop");
+
+ // start recording
+ while (!exitPending()) {
+ if (!mActive) {
+ mLock.lock();
+ if (!mActive && !exitPending()) {
+ LOGV("AudioRecordThread: loop stopping");
+ mWaitWorkCV.wait(mLock);
+ LOGV("AudioRecordThread: loop starting");
+ }
+ mLock.unlock();
+ } else {
+ // promote strong ref so track isn't deleted while we access it
+ sp<RecordTrack> t = mRecordTrack.promote();
+
+ // 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) {
+ LOGE("Error reading audio input");
+ sleep(1);
+ }
+ t->releaseBuffer(&mBuffer);
+ }
+
+ // client isn't retrieving buffers fast enough
+ else {
+ if (!t->setOverflow())
+ LOGW("AudioRecordThread: buffer overflow");
+ }
+ }
+ };
+
+ // 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;
+ }
+ mRecordTrack = recordTrack;
+ mInput = input;
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::AudioRecordThread::start()
+{
+ LOGV("AudioRecordThread::start");
+ AutoMutex lock(&mLock);
+ if (mActive) return -EBUSY;
+
+ sp<RecordTrack> t = mRecordTrack.promote();
+ if (t == 0) return UNKNOWN_ERROR;
+
+ // signal thread to start
+ LOGV("Signal record thread");
+ mActive = true;
+ mWaitWorkCV.signal();
+ return NO_ERROR;
+}
+
+void AudioFlinger::AudioRecordThread::stop() {
+ LOGV("AudioRecordThread::stop");
+ AutoMutex lock(&mLock);
+ if (mActive) {
+ mActive = false;
+ mWaitWorkCV.signal();
+ }
+}
+
+void AudioFlinger::AudioRecordThread::exit()
+{
+ LOGV("AudioRecordThread::exit");
+ AutoMutex lock(&mLock);
+ requestExit();
+ mWaitWorkCV.signal();
+}
+
+
+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)
+{
+ return BnAudioFlinger::onTransact(code, data, reply, flags);
+}
+
+// ----------------------------------------------------------------------------
+void AudioFlinger::instantiate() {
+ defaultServiceManager()->addService(
+ String16("media.audio_flinger"), new AudioFlinger());
+}
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
new file mode 100644
index 0000000..8c02617
--- /dev/null
+++ b/libs/audioflinger/AudioFlinger.h
@@ -0,0 +1,490 @@
+/* //device/include/server/AudioFlinger/AudioFlinger.h
+**
+** 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
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_AUDIO_FLINGER_H
+#define ANDROID_AUDIO_FLINGER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <media/IAudioFlinger.h>
+#include <media/IAudioTrack.h>
+#include <media/IAudioRecord.h>
+#include <media/AudioTrack.h>
+
+#include <utils/Atomic.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+#include <utils/MemoryDealer.h>
+#include <utils/KeyedVector.h>
+#include <utils/SortedVector.h>
+
+#include <hardware/AudioHardwareInterface.h>
+
+#include "AudioBufferProvider.h"
+
+namespace android {
+
+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 ))
+
+// ----------------------------------------------------------------------------
+
+class AudioFlinger : public BnAudioFlinger, protected Thread
+{
+public:
+ static void instantiate();
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ // Thread virtuals
+ virtual bool threadLoop();
+ virtual status_t readyToRun();
+ virtual void onFirstRef();
+
+ // IAudioFlinger interface
+ virtual sp<IAudioTrack> createTrack(
+ pid_t pid,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ uint32_t flags);
+
+ virtual uint32_t sampleRate() const;
+ virtual int channelCount() const;
+ virtual int format() const;
+ virtual size_t frameCount() const;
+
+ virtual status_t setMasterVolume(float value);
+ virtual status_t setMasterMute(bool muted);
+
+ virtual float masterVolume() const;
+ virtual bool masterMute() const;
+
+ virtual status_t setStreamVolume(int stream, float value);
+ virtual status_t setStreamMute(int stream, bool muted);
+
+ virtual float streamVolume(int stream) const;
+ virtual bool streamMute(int stream) const;
+
+ virtual status_t setRouting(int mode, uint32_t routes, uint32_t mask);
+ virtual uint32_t getRouting(int mode) const;
+
+ virtual status_t setMode(int mode);
+ virtual int getMode() const;
+
+ virtual status_t setMicMute(bool state);
+ virtual bool getMicMute() const;
+
+ virtual bool isMusicActive() const;
+
+ virtual status_t setParameter(const char* key, const char* value);
+
+ enum hardware_call_state {
+ AUDIO_HW_IDLE = 0,
+ AUDIO_HW_INIT,
+ AUDIO_HW_OUTPUT_OPEN,
+ AUDIO_HW_OUTPUT_CLOSE,
+ AUDIO_HW_INPUT_OPEN,
+ AUDIO_HW_INPUT_CLOSE,
+ AUDIO_HW_STANDBY,
+ AUDIO_HW_SET_MASTER_VOLUME,
+ AUDIO_HW_GET_ROUTING,
+ AUDIO_HW_SET_ROUTING,
+ AUDIO_HW_GET_MODE,
+ AUDIO_HW_SET_MODE,
+ AUDIO_HW_GET_MIC_MUTE,
+ AUDIO_HW_SET_MIC_MUTE,
+ AUDIO_SET_VOICE_VOLUME,
+ AUDIO_SET_PARAMETER,
+ };
+
+ // record interface
+ virtual sp<IAudioRecord> openRecord(
+ pid_t pid,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ uint32_t flags);
+
+ virtual status_t onTransact(
+ uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags);
+
+private:
+ AudioFlinger();
+ virtual ~AudioFlinger();
+
+ // 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:
+ Client(const sp<AudioFlinger>& audioFlinger, pid_t pid);
+ virtual ~Client();
+ const sp<MemoryDealer>& heap() const;
+ pid_t pid() const { return mPid; }
+ private:
+ Client(const Client&);
+ Client& operator = (const Client&);
+ sp<AudioFlinger> mAudioFlinger;
+ sp<MemoryDealer> mMemoryDealer;
+ pid_t mPid;
+ };
+
+
+ // --- Track ---
+ class TrackHandle;
+ class RecordHandle;
+ class AudioRecordThread;
+
+ // base for record and playback
+ class TrackBase : public AudioBufferProvider, public RefBase {
+
+ public:
+ enum track_state {
+ IDLE,
+ TERMINATED,
+ STOPPED,
+ RESUMING,
+ ACTIVE,
+ PAUSING,
+ PAUSED
+ };
+
+ enum track_flags {
+ 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);
+ ~TrackBase();
+
+ virtual status_t start() = 0;
+ virtual void stop() = 0;
+ sp<IMemory> getCblk() const;
+
+ protected:
+ friend class AudioFlinger;
+ friend class RecordHandle;
+
+ TrackBase(const TrackBase&);
+ TrackBase& operator = (const TrackBase&);
+
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
+ virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
+
+ audio_track_cblk_t* cblk() const {
+ return mCblk;
+ }
+
+ int type() const {
+ return mStreamType;
+ }
+
+ int format() const {
+ return mFormat;
+ }
+
+ int channelCount() const {
+ return mChannelCount;
+ }
+
+ int bufferCount() const {
+ return mBufferCount;
+ }
+
+ int sampleRate() const;
+
+ void* getBuffer(int n) const {
+ return (char*)mBuffers + n * mBufferSize;
+ }
+
+ int name() const {
+ return mName;
+ }
+
+ bool isStopped() const {
+ return mState == STOPPED;
+ }
+
+ bool isTerminated() const {
+ return mState == TERMINATED;
+ }
+
+ bool step();
+ void reset();
+
+ sp<AudioFlinger> mAudioFlinger;
+ sp<Client> mClient;
+ 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;
+ int mName;
+ // we don't really need a lock for these
+ int mState;
+ int mClientTid;
+ };
+
+ // playback track
+ class Track : public TrackBase {
+ public:
+ Track( const sp<AudioFlinger>& audioFlinger,
+ const sp<Client>& client,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ int bufferSize);
+ ~Track();
+
+ void dump(char* buffer, size_t size);
+ virtual status_t start();
+ virtual void stop();
+ void pause();
+
+ void flush();
+ void destroy();
+ void mute(bool);
+ void setVolume(float left, float right);
+
+ private:
+ friend class AudioFlinger;
+ friend class TrackHandle;
+
+ Track(const Track&);
+ Track& operator = (const Track&);
+
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+
+ bool isMuted() const {
+ return mMute;
+ }
+
+ bool isPausing() const {
+ return mState == PAUSING;
+ }
+
+ bool isPaused() const {
+ return mState == PAUSED;
+ }
+
+ bool isReady(uint32_t u, int32_t s) const;
+
+ void setPaused() { mState = PAUSED; }
+ void reset();
+
+ // we don't really need a lock for these
+ float mVolume[2];
+ volatile bool mMute;
+ // FILLED state is used for suppressing volume ramp at begin of playing
+ enum {FS_FILLING, FS_FILLED, FS_ACTIVE};
+ mutable uint8_t mFillingUpStatus;
+ int8_t mRetryCount;
+ }; // end of Track
+
+ friend class AudioBuffer;
+
+ class TrackHandle : public android::BnAudioTrack {
+ public:
+ TrackHandle(const sp<Track>& track);
+ virtual ~TrackHandle();
+ virtual status_t start();
+ virtual void stop();
+ virtual void flush();
+ virtual void mute(bool);
+ virtual void pause();
+ virtual void setVolume(float left, float right);
+ virtual sp<IMemory> getCblk() const;
+ virtual status_t onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+ private:
+ sp<Track> mTrack;
+ };
+
+ struct stream_type_t {
+ stream_type_t()
+ : volume(1.0f),
+ mute(false)
+ {
+ }
+ float volume;
+ bool mute;
+ };
+
+ friend class Client;
+ friend class Track;
+
+
+ void removeClient(pid_t pid);
+
+ status_t addTrack(const sp<Track>& track);
+ void removeTrack(wp<Track> track, int name);
+ void remove_track_l(wp<Track> track, int name);
+ void destroyTrack(const sp<Track>& track);
+
+ AudioMixer& audioMixer() {
+ return *mAudioMixer;
+ }
+
+ // record track
+ class RecordTrack : public TrackBase {
+ public:
+ RecordTrack( const sp<AudioFlinger>& audioFlinger,
+ const sp<Client>& client,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ int bufferSize);
+ ~RecordTrack();
+
+ virtual status_t start();
+ virtual void stop();
+
+ bool overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
+ bool setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
+
+ private:
+ friend class AudioFlinger;
+ friend class RecordHandle;
+ friend class AudioRecordThread;
+
+ RecordTrack(const Track&);
+ RecordTrack& operator = (const Track&);
+
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+
+ bool mOverflow;
+ };
+
+ class RecordHandle : public android::BnAudioRecord {
+ public:
+ RecordHandle(const sp<RecordTrack>& recordTrack);
+ virtual ~RecordHandle();
+ virtual status_t start();
+ virtual void stop();
+ virtual sp<IMemory> getCblk() const;
+ virtual status_t onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+ private:
+ sp<RecordTrack> mRecordTrack;
+ };
+
+ // record thread
+ class AudioRecordThread : public Thread
+ {
+ public:
+ AudioRecordThread(const sp<AudioFlinger>& audioFlinger);
+ 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();
+ void exit();
+
+ bool isOpen() { return bool(mRecordTrack != NULL); }
+
+ private:
+ AudioRecordThread();
+ sp<AudioFlinger> mAudioFlinger;
+ wp<RecordTrack> mRecordTrack;
+ AudioStreamIn* mInput;
+ Mutex mLock;
+ Condition mWaitWorkCV;
+ AudioBufferProvider::Buffer mBuffer;
+ volatile bool mActive;
+ };
+
+ friend class AudioRecordThread;
+
+ sp<AudioRecordThread> audioRecordThread();
+ void endRecord();
+ status_t startRecord();
+ void stopRecord();
+ void exitRecord();
+
+ AudioHardwareInterface* audioHardware() { return mAudioHardware; }
+
+ mutable Mutex mHardwareLock;
+ mutable Mutex mLock;
+ mutable Condition mWaitWorkCV;
+ DefaultKeyedVector< pid_t, wp<Client> > mClients;
+ SortedVector< wp<Track> > mActiveTracks;
+ SortedVector< sp<Track> > mTracks;
+ float mMasterVolume;
+ uint32_t mMasterRouting;
+ bool mMasterMute;
+ stream_type_t mStreamTypes[AudioTrack::NUM_STREAM_TYPES];
+
+ AudioMixer* mAudioMixer;
+ AudioHardwareInterface* mAudioHardware;
+ 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;
+ int mNumWrites;
+ int mNumDelayedWrites;
+ bool mStandby;
+ bool mInWrite;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_FLINGER_H
diff --git a/libs/audioflinger/AudioHardwareGeneric.cpp b/libs/audioflinger/AudioHardwareGeneric.cpp
new file mode 100644
index 0000000..b1e5b7f
--- /dev/null
+++ b/libs/audioflinger/AudioHardwareGeneric.cpp
@@ -0,0 +1,293 @@
+/*
+**
+** 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
+**
+** 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 <stdint.h>
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sched.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#define LOG_TAG "AudioHardware"
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "AudioHardwareGeneric.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static char const * const kAudioDeviceName = "/dev/eac";
+
+// ----------------------------------------------------------------------------
+
+AudioHardwareGeneric::AudioHardwareGeneric()
+ : mOutput(0), mInput(0), mFd(-1), mMicMute(false)
+{
+ mFd = ::open(kAudioDeviceName, O_RDWR);
+}
+
+AudioHardwareGeneric::~AudioHardwareGeneric()
+{
+ if (mFd >= 0) ::close(mFd);
+ delete mOutput;
+ delete mInput;
+}
+
+status_t AudioHardwareGeneric::initCheck()
+{
+ if (mFd >= 0) {
+ if (::access(kAudioDeviceName, O_RDWR) == NO_ERROR)
+ return NO_ERROR;
+ }
+ return NO_INIT;
+}
+
+status_t AudioHardwareGeneric::standby()
+{
+ // Implement: audio hardware to standby mode
+ return NO_ERROR;
+}
+
+AudioStreamOut* AudioHardwareGeneric::openOutputStream(
+ int format, int channelCount, uint32_t sampleRate)
+{
+ AutoMutex lock(mLock);
+
+ // only one output stream allowed
+ if (mOutput) return 0;
+
+ // create new output stream
+ AudioStreamOutGeneric* out = new AudioStreamOutGeneric();
+ if (out->set(this, mFd, format, channelCount, sampleRate) == NO_ERROR) {
+ mOutput = out;
+ } else {
+ delete out;
+ }
+ return mOutput;
+}
+
+void AudioHardwareGeneric::closeOutputStream(AudioStreamOutGeneric* out) {
+ if (out == mOutput) mOutput = 0;
+}
+
+AudioStreamIn* AudioHardwareGeneric::openInputStream(
+ int format, int channelCount, uint32_t sampleRate)
+{
+ AutoMutex lock(mLock);
+
+ // only one input stream allowed
+ if (mInput) return 0;
+
+ // create new output stream
+ AudioStreamInGeneric* in = new AudioStreamInGeneric();
+ if (in->set(this, mFd, format, channelCount, sampleRate) == NO_ERROR) {
+ mInput = in;
+ } else {
+ delete in;
+ }
+ return mInput;
+}
+
+void AudioHardwareGeneric::closeInputStream(AudioStreamInGeneric* in) {
+ if (in == mInput) mInput = 0;
+}
+
+status_t AudioHardwareGeneric::setVoiceVolume(float v)
+{
+ // Implement: set voice volume
+ return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::setMasterVolume(float v)
+{
+ // Implement: set master volume
+ // return error - software mixer will handle it
+ return INVALID_OPERATION;
+}
+
+status_t AudioHardwareGeneric::setMicMute(bool state)
+{
+ mMicMute = state;
+ return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::getMicMute(bool* state)
+{
+ *state = mMicMute;
+ return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::dumpInternals(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ result.append("AudioHardwareGeneric::dumpInternals\n");
+ snprintf(buffer, SIZE, "\tmFd: %d mMicMute: %s\n", mFd, mMicMute? "true": "false");
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::dump(int fd, const Vector<String16>& args)
+{
+ dumpInternals(fd, args);
+ if (mInput) {
+ mInput->dump(fd, args);
+ }
+ if (mOutput) {
+ mOutput->dump(fd, args);
+ }
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t AudioStreamOutGeneric::set(
+ AudioHardwareGeneric *hw,
+ int fd,
+ int format,
+ int channels,
+ uint32_t 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;
+
+ mAudioHardware = hw;
+ mFd = fd;
+ return NO_ERROR;
+}
+
+AudioStreamOutGeneric::~AudioStreamOutGeneric()
+{
+ if (mAudioHardware)
+ mAudioHardware->closeOutputStream(this);
+}
+
+ssize_t AudioStreamOutGeneric::write(const void* buffer, size_t bytes)
+{
+ Mutex::Autolock _l(mLock);
+ return ssize_t(::write(mFd, buffer, bytes));
+}
+
+status_t AudioStreamOutGeneric::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, SIZE, "AudioStreamOutGeneric::dump\n");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tformat: %d\n", format());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+// record functions
+status_t AudioStreamInGeneric::set(
+ AudioHardwareGeneric *hw,
+ int fd,
+ int format,
+ int channels,
+ uint32_t rate)
+{
+ // FIXME: remove logging
+ LOGD("AudioStreamInGeneric::set(%p, %d, %d, %d, %u)", hw, fd, format, channels, rate);
+ // check values
+ if ((format != AudioSystem::PCM_16_BIT) ||
+ (channels != channelCount()) ||
+ (rate != sampleRate())) {
+ LOGE("Error opening input channel");
+ return BAD_VALUE;
+ }
+
+ mAudioHardware = hw;
+ mFd = fd;
+ return NO_ERROR;
+}
+
+AudioStreamInGeneric::~AudioStreamInGeneric()
+{
+ // FIXME: remove logging
+ LOGD("AudioStreamInGeneric destructor");
+ if (mAudioHardware)
+ mAudioHardware->closeInputStream(this);
+}
+
+ssize_t AudioStreamInGeneric::read(void* buffer, ssize_t bytes)
+{
+ // FIXME: remove logging
+ LOGD("AudioStreamInGeneric::read(%p, %d) from fd %d", buffer, bytes, mFd);
+ AutoMutex lock(mLock);
+ if (mFd < 0) {
+ LOGE("Attempt to read from unopened device");
+ return NO_INIT;
+ }
+ return ::read(mFd, buffer, bytes);
+}
+
+status_t AudioStreamInGeneric::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, SIZE, "AudioStreamInGeneric::dump\n");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tformat: %d\n", format());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioHardwareGeneric.h b/libs/audioflinger/AudioHardwareGeneric.h
new file mode 100644
index 0000000..10cc45d
--- /dev/null
+++ b/libs/audioflinger/AudioHardwareGeneric.h
@@ -0,0 +1,135 @@
+/*
+**
+** 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
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_AUDIO_HARDWARE_GENERIC_H
+#define ANDROID_AUDIO_HARDWARE_GENERIC_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+
+#include <hardware/AudioHardwareInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class AudioHardwareGeneric;
+
+class AudioStreamOutGeneric : public AudioStreamOut {
+public:
+ AudioStreamOutGeneric() : mAudioHardware(0), mFd(-1) {}
+ virtual ~AudioStreamOutGeneric();
+
+ virtual status_t set(
+ AudioHardwareGeneric *hw,
+ int mFd,
+ int format,
+ int channelCount,
+ uint32_t sampleRate);
+
+ virtual uint32_t sampleRate() const { return 44100; }
+ virtual size_t bufferSize() const { return 4096; }
+ virtual int channelCount() const { return 2; }
+ virtual int format() const { return AudioSystem::PCM_16_BIT; }
+ 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);
+
+private:
+ AudioHardwareGeneric *mAudioHardware;
+ Mutex mLock;
+ int mFd;
+};
+
+class AudioStreamInGeneric : public AudioStreamIn {
+public:
+ AudioStreamInGeneric() : mAudioHardware(0), mFd(-1) {}
+ virtual ~AudioStreamInGeneric();
+
+ virtual status_t set(
+ AudioHardwareGeneric *hw,
+ int mFd,
+ int format,
+ int channelCount,
+ uint32_t sampleRate);
+
+ uint32_t sampleRate() const { return 8000; }
+ virtual size_t bufferSize() const { return 320; }
+ virtual int channelCount() const { return 1; }
+ virtual int format() const { return AudioSystem::PCM_16_BIT; }
+ 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);
+
+private:
+ AudioHardwareGeneric *mAudioHardware;
+ Mutex mLock;
+ int mFd;
+};
+
+
+class AudioHardwareGeneric : public AudioHardwareInterface
+{
+public:
+ AudioHardwareGeneric();
+ virtual ~AudioHardwareGeneric();
+ 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);
+
+ virtual status_t setParameter(const char* key, const char* value)
+ { return NO_ERROR; }
+
+ // create I/O streams
+ virtual AudioStreamOut* openOutputStream(
+ int format=0,
+ int channelCount=0,
+ uint32_t sampleRate=0);
+
+ virtual AudioStreamIn* openInputStream(
+ int format,
+ int channelCount,
+ uint32_t sampleRate);
+
+ void closeOutputStream(AudioStreamOutGeneric* out);
+ void closeInputStream(AudioStreamInGeneric* in);
+protected:
+ virtual status_t doRouting() { return NO_ERROR; }
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+private:
+ status_t dumpInternals(int fd, const Vector<String16>& args);
+
+ Mutex mLock;
+ AudioStreamOutGeneric *mOutput;
+ AudioStreamInGeneric *mInput;
+ int mFd;
+ bool mMicMute;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_HARDWARE_GENERIC_H
diff --git a/libs/audioflinger/AudioHardwareInterface.cpp b/libs/audioflinger/AudioHardwareInterface.cpp
new file mode 100644
index 0000000..7387b3d
--- /dev/null
+++ b/libs/audioflinger/AudioHardwareInterface.cpp
@@ -0,0 +1,240 @@
+/*
+**
+** 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
+**
+** 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 <cutils/properties.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LOG_TAG "AudioHardwareInterface"
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "AudioHardwareStub.h"
+#include "AudioHardwareGeneric.h"
+
+// #define DUMP_FLINGER_OUT // if defined allows recording samples in a file
+#ifdef DUMP_FLINGER_OUT
+#include "AudioDumpInterface.h"
+#endif
+
+
+// change to 1 to log routing calls
+#define LOG_ROUTING_CALLS 0
+
+namespace android {
+
+#if LOG_ROUTING_CALLS
+static const char* routingModeStrings[] =
+{
+ "OUT OF RANGE",
+ "INVALID",
+ "CURRENT",
+ "NORMAL",
+ "RINGTONE",
+ "IN_CALL"
+};
+
+static const char* routeStrings[] =
+{
+ "EARPIECE ",
+ "SPEAKER ",
+ "BLUETOOTH ",
+ "HEADSET "
+};
+static const char* routeNone = "NONE";
+
+static const char* displayMode(int mode)
+{
+ if ((mode < -2) || (mode > 2))
+ return routingModeStrings[0];
+ return routingModeStrings[mode+3];
+}
+
+static const char* displayRoutes(uint32_t routes)
+{
+ static char routeStr[80];
+ if (routes == 0)
+ return routeNone;
+ routeStr[0] = 0;
+ int bitMask = 1;
+ for (int i = 0; i < 4; ++i, bitMask <<= 1) {
+ if (routes & bitMask) {
+ strcat(routeStr, routeStrings[i]);
+ }
+ }
+ routeStr[strlen(routeStr)-1] = 0;
+ return routeStr;
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+AudioHardwareInterface* AudioHardwareInterface::create()
+{
+ /*
+ * FIXME: This code needs to instantiate the correct audio device
+ * interface. For now - we use compile-time switches.
+ */
+ AudioHardwareInterface* hw = 0;
+ char value[PROPERTY_VALUE_MAX];
+
+#ifdef GENERIC_AUDIO
+ hw = new AudioHardwareGeneric();
+#else
+ // if running in emulation - use the emulator driver
+ if (property_get("ro.kernel.qemu", value, 0)) {
+ LOGD("Running in emulation - using generic audio driver");
+ hw = new AudioHardwareGeneric();
+ }
+ else {
+ LOGV("Creating Vendor Specific AudioHardware");
+ hw = createAudioHardware();
+ }
+#endif
+ if (hw->initCheck() != NO_ERROR) {
+ LOGW("Using stubbed audio hardware. No sound will be produced.");
+ delete hw;
+ hw = new AudioHardwareStub();
+ }
+
+#ifdef DUMP_FLINGER_OUT
+ // 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.
+
+ // 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;
+ }
+#endif
+ return hw;
+}
+
+AudioStreamOut::~AudioStreamOut()
+{
+}
+
+AudioStreamIn::~AudioStreamIn() {}
+
+AudioHardwareInterface::AudioHardwareInterface()
+{
+ // force a routing update on initialization
+ memset(&mRoutes, 0, sizeof(mRoutes));
+ mMode = 0;
+}
+
+// generics for audio routing - the real work is done in doRouting
+status_t AudioHardwareInterface::setRouting(int mode, uint32_t routes)
+{
+#if LOG_ROUTING_CALLS
+ LOGD("setRouting: mode=%s, routes=[%s]", displayMode(mode), displayRoutes(routes));
+#endif
+ if (mode == AudioSystem::MODE_CURRENT)
+ mode = mMode;
+ if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
+ return BAD_VALUE;
+ uint32_t old = mRoutes[mode];
+ mRoutes[mode] = routes;
+ if ((mode != mMode) || (old == routes))
+ return NO_ERROR;
+#if LOG_ROUTING_CALLS
+ const char* oldRouteStr = strdup(displayRoutes(old));
+ LOGD("doRouting: mode=%s, old route=[%s], new route=[%s]",
+ displayMode(mode), oldRouteStr, displayRoutes(routes));
+ delete oldRouteStr;
+#endif
+ return doRouting();
+}
+
+status_t AudioHardwareInterface::getRouting(int mode, uint32_t* routes)
+{
+ if (mode == AudioSystem::MODE_CURRENT)
+ mode = mMode;
+ if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
+ return BAD_VALUE;
+ *routes = mRoutes[mode];
+#if LOG_ROUTING_CALLS
+ LOGD("getRouting: mode=%s, routes=[%s]",
+ displayMode(mode), displayRoutes(*routes));
+#endif
+ return NO_ERROR;
+}
+
+status_t AudioHardwareInterface::setMode(int mode)
+{
+#if LOG_ROUTING_CALLS
+ LOGD("setMode(%s)", displayMode(mode));
+#endif
+ if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
+ return BAD_VALUE;
+ if (mMode == mode)
+ return NO_ERROR;
+#if LOG_ROUTING_CALLS
+ LOGD("doRouting: old mode=%s, new mode=%s route=[%s]",
+ displayMode(mMode), displayMode(mode), displayRoutes(mRoutes[mode]));
+#endif
+ mMode = mode;
+ return doRouting();
+}
+
+status_t AudioHardwareInterface::getMode(int* mode)
+{
+ // Implement: set audio routing
+ *mode = mMode;
+ return NO_ERROR;
+}
+
+status_t AudioHardwareInterface::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)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, SIZE, "AudioHardwareInterface::dumpState\n");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmMode: %d\n", mMode);
+ result.append(buffer);
+ for (int i = 0, n = AudioSystem::NUM_MODES; i < n; ++i) {
+ snprintf(buffer, SIZE, "\tmRoutes[%d]: %d\n", i, mRoutes[i]);
+ result.append(buffer);
+ }
+ ::write(fd, result.string(), result.size());
+ dump(fd, args); // Dump the state of the concrete child.
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioHardwareStub.cpp b/libs/audioflinger/AudioHardwareStub.cpp
new file mode 100644
index 0000000..0046db8
--- /dev/null
+++ b/libs/audioflinger/AudioHardwareStub.cpp
@@ -0,0 +1,175 @@
+/* //device/servers/AudioFlinger/AudioHardwareStub.cpp
+**
+** 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
+**
+** 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 <stdint.h>
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <utils/String8.h>
+
+#include "AudioHardwareStub.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+AudioHardwareStub::AudioHardwareStub() : mMicMute(false)
+{
+}
+
+AudioHardwareStub::~AudioHardwareStub()
+{
+}
+
+status_t AudioHardwareStub::initCheck()
+{
+ return NO_ERROR;
+}
+
+status_t AudioHardwareStub::standby()
+{
+ return NO_ERROR;
+}
+
+AudioStreamOut* AudioHardwareStub::openOutputStream(
+ int format, int channelCount, uint32_t sampleRate)
+{
+ AudioStreamOutStub* out = new AudioStreamOutStub();
+ if (out->set(format, channelCount, sampleRate) == NO_ERROR)
+ return out;
+ delete out;
+ return 0;
+}
+
+AudioStreamIn* AudioHardwareStub::openInputStream(
+ int format, int channelCount, uint32_t sampleRate)
+{
+ AudioStreamInStub* in = new AudioStreamInStub();
+ if (in->set(format, channelCount, sampleRate) == NO_ERROR)
+ return in;
+ delete in;
+ return 0;
+}
+
+status_t AudioHardwareStub::setVoiceVolume(float volume)
+{
+ return NO_ERROR;
+}
+
+status_t AudioHardwareStub::setMasterVolume(float volume)
+{
+ return NO_ERROR;
+}
+
+status_t AudioHardwareStub::dumpInternals(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ result.append("AudioHardwareStub::dumpInternals\n");
+ snprintf(buffer, SIZE, "\tmMicMute: %s\n", mMicMute? "true": "false");
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioHardwareStub::dump(int fd, const Vector<String16>& args)
+{
+ dumpInternals(fd, args);
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t AudioStreamOutStub::set(int format, int channels, uint32_t rate)
+{
+ // fix up defaults
+ 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()))
+ return NO_ERROR;
+ return BAD_VALUE;
+}
+
+ssize_t AudioStreamOutStub::write(const void* buffer, size_t bytes)
+{
+ // fake timing for audio output
+ usleep(bytes * 1000000 / sizeof(int16_t) / channelCount() / sampleRate());
+ return bytes;
+}
+
+status_t AudioStreamOutStub::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, SIZE, "AudioStreamOutStub::dump\n");
+ snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+ snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+ snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+ snprintf(buffer, SIZE, "\tformat: %d\n", format());
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t AudioStreamInStub::set(int format, int channels, uint32_t rate)
+{
+ if ((format == AudioSystem::PCM_16_BIT) &&
+ (channels == channelCount()) &&
+ (rate == sampleRate()))
+ return NO_ERROR;
+ return BAD_VALUE;
+}
+
+ssize_t AudioStreamInStub::read(void* buffer, ssize_t bytes)
+{
+ // fake timing for audio input
+ usleep(bytes * 1000000 / sizeof(int16_t) / channelCount() / sampleRate());
+ memset(buffer, 0, bytes);
+ return bytes;
+}
+
+status_t AudioStreamInStub::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, SIZE, "AudioStreamInStub::dump\n");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tformat: %d\n", format());
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioHardwareStub.h b/libs/audioflinger/AudioHardwareStub.h
new file mode 100644
index 0000000..1a61552
--- /dev/null
+++ b/libs/audioflinger/AudioHardwareStub.h
@@ -0,0 +1,95 @@
+/* //device/servers/AudioFlinger/AudioHardwareStub.h
+**
+** 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
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_AUDIO_HARDWARE_STUB_H
+#define ANDROID_AUDIO_HARDWARE_STUB_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <hardware/AudioHardwareInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class AudioStreamOutStub : public AudioStreamOut {
+public:
+ virtual status_t set(int format, int channelCount, uint32_t sampleRate);
+ virtual uint32_t sampleRate() const { return 44100; }
+ virtual size_t bufferSize() const { return 4096; }
+ virtual int channelCount() const { return 2; }
+ virtual int format() const { return AudioSystem::PCM_16_BIT; }
+ 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);
+};
+
+class AudioStreamInStub : public AudioStreamIn {
+public:
+ virtual status_t set(int format, int channelCount, uint32_t sampleRate);
+ virtual uint32_t sampleRate() const { return 8000; }
+ virtual size_t bufferSize() const { return 320; }
+ virtual int channelCount() const { return 1; }
+ virtual int format() const { return AudioSystem::PCM_16_BIT; }
+ 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);
+};
+
+class AudioHardwareStub : public AudioHardwareInterface
+{
+public:
+ AudioHardwareStub();
+ virtual ~AudioHardwareStub();
+ 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) { mMicMute = state; return NO_ERROR; }
+ virtual status_t getMicMute(bool* state) { *state = mMicMute ; return NO_ERROR; }
+
+ virtual status_t setParameter(const char* key, const char* value)
+ { return NO_ERROR; }
+
+ // create I/O streams
+ virtual AudioStreamOut* openOutputStream(
+ int format=0,
+ int channelCount=0,
+ uint32_t sampleRate=0);
+
+ virtual AudioStreamIn* openInputStream(
+ int format,
+ int channelCount,
+ uint32_t sampleRate);
+
+protected:
+ virtual status_t doRouting() { return NO_ERROR; }
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ bool mMicMute;
+private:
+ status_t dumpInternals(int fd, const Vector<String16>& args);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_HARDWARE_STUB_H
diff --git a/libs/audioflinger/AudioMixer.cpp b/libs/audioflinger/AudioMixer.cpp
new file mode 100644
index 0000000..9f1b17f
--- /dev/null
+++ b/libs/audioflinger/AudioMixer.cpp
@@ -0,0 +1,857 @@
+/* //device/include/server/AudioFlinger/AudioMixer.cpp
+**
+** 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
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "AudioMixer"
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include "AudioMixer.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+static inline int16_t clamp16(int32_t sample)
+{
+ if ((sample>>15) ^ (sample>>31))
+ sample = 0x7FFF ^ (sample>>31);
+ return sample;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate)
+ : mActiveTrack(0), mTrackNames(0), mSampleRate(sampleRate)
+{
+ mState.enabledTracks= 0;
+ mState.needsChanged = 0;
+ mState.frameCount = frameCount;
+ mState.outputTemp = 0;
+ mState.resampleTemp = 0;
+ mState.hook = process__nop;
+ track_t* t = mState.tracks;
+ for (int i=0 ; i<32 ; i++) {
+ t->needs = 0;
+ t->volume[0] = UNITY_GAIN;
+ t->volume[1] = UNITY_GAIN;
+ t->volumeInc[0] = 0;
+ t->volumeInc[1] = 0;
+ t->channelCount = 2;
+ t->enabled = 0;
+ t->format = 16;
+ t->buffer.raw = 0;
+ t->bufferProvider = 0;
+ t->hook = 0;
+ t->resampler = 0;
+ t->sampleRate = mSampleRate;
+ t->in = 0;
+ t++;
+ }
+}
+
+ AudioMixer::~AudioMixer()
+ {
+ track_t* t = mState.tracks;
+ for (int i=0 ; i<32 ; i++) {
+ delete t->resampler;
+ t++;
+ }
+ delete [] mState.outputTemp;
+ delete [] mState.resampleTemp;
+ }
+
+ int AudioMixer::getTrackName()
+ {
+ uint32_t names = mTrackNames;
+ uint32_t mask = 1;
+ int n = 0;
+ while (names & mask) {
+ mask <<= 1;
+ n++;
+ }
+ if (mask) {
+ LOGV("add track (%d)", n);
+ mTrackNames |= mask;
+ return TRACK0 + n;
+ }
+ return -1;
+ }
+
+ void AudioMixer::invalidateState(uint32_t mask)
+ {
+ if (mask) {
+ mState.needsChanged |= mask;
+ mState.hook = process__validate;
+ }
+ }
+
+ void AudioMixer::deleteTrackName(int name)
+ {
+ name -= TRACK0;
+ if (uint32_t(name) < MAX_NUM_TRACKS) {
+ LOGV("deleteTrackName(%d)", name);
+ track_t& track(mState.tracks[ name ]);
+ if (track.enabled != 0) {
+ track.enabled = 0;
+ invalidateState(1<<name);
+ }
+ if (track.resampler) {
+ // delete the resampler
+ delete track.resampler;
+ track.resampler = 0;
+ track.sampleRate = mSampleRate;
+ invalidateState(1<<name);
+ }
+ track.volumeInc[0] = 0;
+ track.volumeInc[1] = 0;
+ mTrackNames &= ~(1<<name);
+ }
+ }
+
+status_t AudioMixer::enable(int name)
+{
+ switch (name) {
+ case MIXING: {
+ if (mState.tracks[ mActiveTrack ].enabled != 1) {
+ mState.tracks[ mActiveTrack ].enabled = 1;
+ LOGV("enable(%d)", mActiveTrack);
+ invalidateState(1<<mActiveTrack);
+ }
+ } break;
+ default:
+ return NAME_NOT_FOUND;
+ }
+ return NO_ERROR;
+}
+
+status_t AudioMixer::disable(int name)
+{
+ switch (name) {
+ case MIXING: {
+ if (mState.tracks[ mActiveTrack ].enabled != 0) {
+ mState.tracks[ mActiveTrack ].enabled = 0;
+ LOGV("disable(%d)", mActiveTrack);
+ invalidateState(1<<mActiveTrack);
+ }
+ } break;
+ default:
+ return NAME_NOT_FOUND;
+ }
+ return NO_ERROR;
+}
+
+status_t AudioMixer::setActiveTrack(int track)
+{
+ if (uint32_t(track-TRACK0) >= MAX_NUM_TRACKS) {
+ return BAD_VALUE;
+ }
+ mActiveTrack = track - TRACK0;
+ return NO_ERROR;
+}
+
+status_t AudioMixer::setParameter(int target, int name, int value)
+{
+ switch (target) {
+ case TRACK:
+ if (name == CHANNEL_COUNT) {
+ if ((uint32_t(value) <= MAX_NUM_CHANNELS) && (value)) {
+ if (mState.tracks[ mActiveTrack ].channelCount != value) {
+ mState.tracks[ mActiveTrack ].channelCount = value;
+ LOGV("setParameter(TRACK, CHANNEL_COUNT, %d)", value);
+ invalidateState(1<<mActiveTrack);
+ }
+ return NO_ERROR;
+ }
+ }
+ break;
+ case RESAMPLE:
+ if (name == SAMPLE_RATE) {
+ if (value > 0) {
+ track_t& track = mState.tracks[ mActiveTrack ];
+ if (track.setResampler(uint32_t(value), mSampleRate)) {
+ LOGV("setParameter(RESAMPLE, SAMPLE_RATE, %u)",
+ uint32_t(value));
+ invalidateState(1<<mActiveTrack);
+ }
+ return NO_ERROR;
+ }
+ }
+ break;
+ case RAMP_VOLUME:
+ case VOLUME:
+ if ((uint32_t(name-VOLUME0) < MAX_NUM_CHANNELS)) {
+ track_t& track = mState.tracks[ mActiveTrack ];
+ if (track.volume[name-VOLUME0] != value) {
+ track.prevVolume[name-VOLUME0] = track.volume[name-VOLUME0] << 16;
+ track.volume[name-VOLUME0] = value;
+ if (target == VOLUME) {
+ track.prevVolume[name-VOLUME0] = value << 16;
+ track.volumeInc[name-VOLUME0] = 0;
+ } else {
+ int32_t d = (value<<16) - track.prevVolume[name-VOLUME0];
+ int32_t volInc = d / int32_t(mState.frameCount);
+ track.volumeInc[name-VOLUME0] = volInc;
+ if (volInc == 0) {
+ track.prevVolume[name-VOLUME0] = value << 16;
+ }
+ }
+ invalidateState(1<<mActiveTrack);
+ }
+ return NO_ERROR;
+ }
+ break;
+ }
+ return BAD_VALUE;
+}
+
+bool AudioMixer::track_t::setResampler(uint32_t value, uint32_t devSampleRate)
+{
+ if (value!=devSampleRate || resampler) {
+ if (sampleRate != value) {
+ sampleRate = value;
+ if (resampler == 0) {
+ resampler = AudioResampler::create(
+ format, channelCount, devSampleRate);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AudioMixer::track_t::doesResample() const
+{
+ return resampler != 0;
+}
+
+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]))) {
+ volumeInc[i] = 0;
+ prevVolume[i] = volume[i]<<16;
+ }
+ }
+}
+
+
+status_t AudioMixer::setBufferProvider(AudioBufferProvider* buffer)
+{
+ mState.tracks[ mActiveTrack ].bufferProvider = buffer;
+ return NO_ERROR;
+}
+
+
+
+void AudioMixer::process(void* output)
+{
+ mState.hook(&mState, output);
+}
+
+
+void AudioMixer::process__validate(state_t* state, void* output)
+{
+ LOGW_IF(!state->needsChanged,
+ "in process__validate() but nothing's invalid");
+
+ uint32_t changed = state->needsChanged;
+ state->needsChanged = 0; // clear the validation flag
+
+ // recompute which tracks are enabled / disabled
+ uint32_t enabled = 0;
+ uint32_t disabled = 0;
+ while (changed) {
+ const int i = 31 - __builtin_clz(changed);
+ const uint32_t mask = 1<<i;
+ changed &= ~mask;
+ track_t& t = state->tracks[i];
+ (t.enabled ? enabled : disabled) |= mask;
+ }
+ state->enabledTracks &= ~disabled;
+ state->enabledTracks |= enabled;
+
+ // compute everything we need...
+ int countActiveTracks = 0;
+ int all16BitsStereoNoResample = 1;
+ int resampling = 0;
+ int volumeRamp = 0;
+ uint32_t en = state->enabledTracks;
+ while (en) {
+ const int i = 31 - __builtin_clz(en);
+ en &= ~(1<<i);
+
+ countActiveTracks++;
+ track_t& t = state->tracks[i];
+ uint32_t n = 0;
+ 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) {
+ n |= NEEDS_MUTE_ENABLED;
+ }
+ t.needs = n;
+
+ if ((n & NEEDS_MUTE__MASK) == NEEDS_MUTE_ENABLED) {
+ t.hook = track__nop;
+ } else {
+ if ((n & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
+ all16BitsStereoNoResample = 0;
+ resampling = 1;
+ t.hook = track__genericResample;
+ } else {
+ if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_1){
+ t.hook = track__16BitsMono;
+ all16BitsStereoNoResample = 0;
+ }
+ if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_2){
+ t.hook = track__16BitsStereo;
+ }
+ }
+ }
+ }
+
+ // select the processing hooks
+ state->hook = process__nop;
+ if (countActiveTracks) {
+ if (resampling) {
+ if (!state->outputTemp) {
+ state->outputTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount];
+ }
+ if (!state->resampleTemp) {
+ state->resampleTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount];
+ }
+ state->hook = process__genericResampling;
+ } else {
+ if (state->outputTemp) {
+ delete [] state->outputTemp;
+ state->outputTemp = 0;
+ }
+ if (state->resampleTemp) {
+ delete [] state->resampleTemp;
+ state->resampleTemp = 0;
+ }
+ state->hook = process__genericNoResampling;
+ if (all16BitsStereoNoResample && !volumeRamp) {
+ if (countActiveTracks == 1) {
+ state->hook = process__OneTrack16BitsStereoNoResampling;
+ }
+ }
+ }
+ }
+
+ LOGV("mixer configuration change: %d activeTracks (%08x) "
+ "all16BitsStereoNoResample=%d, resampling=%d, volumeRamp=%d",
+ countActiveTracks, state->enabledTracks,
+ all16BitsStereoNoResample, resampling, volumeRamp);
+
+ state->hook(state, output);
+
+ // Now that the volume ramp has been done, set optimal state and
+ // track hooks for subsequent mixer process
+ if (countActiveTracks) {
+ int allMuted = 1;
+ uint32_t en = state->enabledTracks;
+ while (en) {
+ const int i = 31 - __builtin_clz(en);
+ en &= ~(1<<i);
+ track_t& t = state->tracks[i];
+ if (!t.doesResample() && t.volumeRL == 0)
+ {
+ t.needs |= NEEDS_MUTE_ENABLED;
+ t.hook = track__nop;
+ } else {
+ allMuted = 0;
+ }
+ }
+ if (allMuted) {
+ state->hook = process__nop;
+ } else if (!resampling && all16BitsStereoNoResample) {
+ if (countActiveTracks == 1) {
+ state->hook = process__OneTrack16BitsStereoNoResampling;
+ }
+ }
+ }
+}
+
+static inline
+int32_t mulAdd(int16_t in, int16_t v, int32_t a)
+{
+#if defined(__arm__) && !defined(__thumb__)
+ int32_t out;
+ asm( "smlabb %[out], %[in], %[v], %[a] \n"
+ : [out]"=r"(out)
+ : [in]"%r"(in), [v]"r"(v), [a]"r"(a)
+ : );
+ return out;
+#else
+ return a + in * int32_t(v);
+#endif
+}
+
+static inline
+int32_t mul(int16_t in, int16_t v)
+{
+#if defined(__arm__) && !defined(__thumb__)
+ int32_t out;
+ asm( "smulbb %[out], %[in], %[v] \n"
+ : [out]"=r"(out)
+ : [in]"%r"(in), [v]"r"(v)
+ : );
+ return out;
+#else
+ return in * int32_t(v);
+#endif
+}
+
+static inline
+int32_t mulAddRL(int left, uint32_t inRL, uint32_t vRL, int32_t a)
+{
+#if defined(__arm__) && !defined(__thumb__)
+ int32_t out;
+ if (left) {
+ asm( "smlabb %[out], %[inRL], %[vRL], %[a] \n"
+ : [out]"=r"(out)
+ : [inRL]"%r"(inRL), [vRL]"r"(vRL), [a]"r"(a)
+ : );
+ } else {
+ asm( "smlatt %[out], %[inRL], %[vRL], %[a] \n"
+ : [out]"=r"(out)
+ : [inRL]"%r"(inRL), [vRL]"r"(vRL), [a]"r"(a)
+ : );
+ }
+ return out;
+#else
+ if (left) {
+ return a + int16_t(inRL&0xFFFF) * int16_t(vRL&0xFFFF);
+ } else {
+ return a + int16_t(inRL>>16) * int16_t(vRL>>16);
+ }
+#endif
+}
+
+static inline
+int32_t mulRL(int left, uint32_t inRL, uint32_t vRL)
+{
+#if defined(__arm__) && !defined(__thumb__)
+ int32_t out;
+ if (left) {
+ asm( "smulbb %[out], %[inRL], %[vRL] \n"
+ : [out]"=r"(out)
+ : [inRL]"%r"(inRL), [vRL]"r"(vRL)
+ : );
+ } else {
+ asm( "smultt %[out], %[inRL], %[vRL] \n"
+ : [out]"=r"(out)
+ : [inRL]"%r"(inRL), [vRL]"r"(vRL)
+ : );
+ }
+ return out;
+#else
+ if (left) {
+ return int16_t(inRL&0xFFFF) * int16_t(vRL&0xFFFF);
+ } else {
+ return int16_t(inRL>>16) * int16_t(vRL>>16);
+ }
+#endif
+}
+
+
+void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp)
+{
+ t->resampler->setSampleRate(t->sampleRate);
+
+ // ramp gain - resample to temp buffer and scale/mix in 2nd step
+ if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
+ t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN);
+ memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t));
+ t->resampler->resample(temp, outFrameCount, t->bufferProvider);
+ volumeRampStereo(t, out, outFrameCount, temp);
+ }
+
+ // constant gain
+ else {
+ t->resampler->setVolume(t->volume[0], t->volume[1]);
+ t->resampler->resample(out, outFrameCount, t->bufferProvider);
+ }
+}
+
+void AudioMixer::track__nop(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp)
+{
+}
+
+void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
+{
+ int32_t vl = t->prevVolume[0];
+ int32_t vr = t->prevVolume[1];
+ const int32_t vlInc = t->volumeInc[0];
+ const int32_t vrInc = t->volumeInc[1];
+
+ //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);
+ *out++ += (vr >> 16) * (*temp++ >> 12);
+ vl += vlInc;
+ vr += vrInc;
+ } while (--frameCount);
+
+ t->prevVolume[0] = vl;
+ t->prevVolume[1] = vr;
+ t->adjustVolumeRamp();
+}
+
+void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
+{
+ int16_t const *in = static_cast<int16_t const *>(t->in);
+
+ // ramp gain
+ if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
+ int32_t vl = t->prevVolume[0];
+ int32_t vr = t->prevVolume[1];
+ const int32_t vlInc = t->volumeInc[0];
+ const int32_t vrInc = t->volumeInc[1];
+
+ // LOGD("[1] %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);
+
+ do {
+ *out++ += (vl >> 16) * (int32_t) *in++;
+ *out++ += (vr >> 16) * (int32_t) *in++;
+ vl += vlInc;
+ vr += vrInc;
+ } while (--frameCount);
+
+ t->prevVolume[0] = vl;
+ t->prevVolume[1] = vr;
+ t->adjustVolumeRamp();
+ }
+
+ // constant gain
+ else {
+ const uint32_t vrl = t->volumeRL;
+ do {
+ uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
+ in += 2;
+ out[0] = mulAddRL(1, rl, vrl, out[0]);
+ out[1] = mulAddRL(0, rl, vrl, out[1]);
+ out += 2;
+ } while (--frameCount);
+ }
+ t->in = in;
+}
+
+void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
+{
+ int16_t const *in = static_cast<int16_t const *>(t->in);
+
+ // ramp gain
+ if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
+ int32_t vl = t->prevVolume[0];
+ int32_t vr = t->prevVolume[1];
+ const int32_t vlInc = t->volumeInc[0];
+ const int32_t vrInc = t->volumeInc[1];
+
+ // LOGD("[2] %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);
+
+ do {
+ int32_t l = *in++;
+ *out++ += (vl >> 16) * l;
+ *out++ += (vr >> 16) * l;
+ vl += vlInc;
+ vr += vrInc;
+ } while (--frameCount);
+
+ t->prevVolume[0] = vl;
+ t->prevVolume[1] = vr;
+ t->adjustVolumeRamp();
+ }
+ // constant gain
+ else {
+ const int16_t vl = t->volume[0];
+ const int16_t vr = t->volume[1];
+ do {
+ int16_t l = *in++;
+ out[0] = mulAdd(l, vl, out[0]);
+ out[1] = mulAdd(l, vr, out[1]);
+ out += 2;
+ } while (--frameCount);
+ }
+ t->in = in;
+}
+
+inline
+void AudioMixer::ditherAndClamp(int32_t* out, int32_t const *sums, size_t c)
+{
+ for (size_t i=0 ; i<c ; i++) {
+ int32_t l = *sums++;
+ int32_t r = *sums++;
+ int32_t nl = l >> 12;
+ int32_t nr = r >> 12;
+ l = clamp16(nl);
+ r = clamp16(nr);
+ *out++ = (r<<16) | (l & 0xFFFF);
+ }
+}
+
+// no-op case
+void AudioMixer::process__nop(state_t* state, void* output)
+{
+ // this assumes output 16 bits stereo, no resampling
+ memset(output, 0, state->frameCount*4);
+ uint32_t en = state->enabledTracks;
+ while (en) {
+ 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) {
+ t.bufferProvider->releaseBuffer(&t.buffer);
+ }
+ }
+}
+
+// generic code without resampling
+void AudioMixer::process__genericNoResampling(state_t* state, void* output)
+{
+ int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32)));
+
+ // acquire each track's buffer
+ uint32_t enabledTracks = state->enabledTracks;
+ uint32_t en = enabledTracks;
+ while (en) {
+ const int i = 31 - __builtin_clz(en);
+ en &= ~(1<<i);
+ track_t& t = state->tracks[i];
+ 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)
+ enabledTracks &= ~(1<<i);
+ }
+
+ // this assumes output 16 bits stereo, no resampling
+ int32_t* out = static_cast<int32_t*>(output);
+ size_t numFrames = state->frameCount;
+ do {
+ memset(outTemp, 0, sizeof(outTemp));
+
+ en = enabledTracks;
+ while (en) {
+ const int i = 31 - __builtin_clz(en);
+ en &= ~(1<<i);
+ track_t& t = state->tracks[i];
+ (t.hook)(&t, outTemp, BLOCKSIZE, state->resampleTemp);
+ }
+
+ ditherAndClamp(out, outTemp, BLOCKSIZE);
+ out += BLOCKSIZE;
+
+ numFrames -= BLOCKSIZE;
+ } while (numFrames);
+
+
+ // release each track's buffer
+ en = enabledTracks;
+ while (en) {
+ const int i = 31 - __builtin_clz(en);
+ en &= ~(1<<i);
+ track_t& t = state->tracks[i];
+ t.bufferProvider->releaseBuffer(&t.buffer);
+ }
+}
+
+// generic code with resampling
+void AudioMixer::process__genericResampling(state_t* state, void* output)
+{
+ int32_t* const outTemp = state->outputTemp;
+ const size_t size = sizeof(int32_t) * MAX_NUM_CHANNELS * state->frameCount;
+ memset(outTemp, 0, size);
+
+ int32_t* out = static_cast<int32_t*>(output);
+ size_t numFrames = state->frameCount;
+
+ uint32_t en = state->enabledTracks;
+ while (en) {
+ const int i = 31 - __builtin_clz(en);
+ en &= ~(1<<i);
+ track_t& t = state->tracks[i];
+
+ // this is a little goofy, on the resampling case we don't
+ // acquire/release the buffers because it's done by
+ // the resampler.
+ 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);
+ t.bufferProvider->releaseBuffer(&t.buffer);
+ }
+ }
+ }
+
+ ditherAndClamp(out, outTemp, numFrames);
+}
+
+// one track, 16 bits stereo without resampling is the most common case
+void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, void* output)
+{
+ const int i = 31 - __builtin_clz(state->enabledTracks);
+ 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);
+ }
+
+ t.bufferProvider->releaseBuffer(&b);
+}
+
+// 2 tracks is also a common case
+void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, void* output)
+{
+ int i;
+ uint32_t en = state->enabledTracks;
+
+ 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];
+ int16_t const *in1;
+ const int16_t vl1 = t1.volume[0];
+ const int16_t vr1 = t1.volume[1];
+ size_t numFrames = state->frameCount;
+ 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));
+ }
+ } 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;
+ }
+ }
+
+ 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);
+
+
+ if (t0.buffer.i16 != NULL) {
+ t0.bufferProvider->releaseBuffer(&b0);
+ if (t1.buffer.i16 != NULL) {
+ t1.bufferProvider->releaseBuffer(&b1);
+ } else {
+ delete [] in1;
+ }
+ } else {
+ delete [] in0;
+ if (t1.buffer.i16 != NULL) {
+ t1.bufferProvider->releaseBuffer(&b1);
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/libs/audioflinger/AudioMixer.h b/libs/audioflinger/AudioMixer.h
new file mode 100644
index 0000000..9ca109f
--- /dev/null
+++ b/libs/audioflinger/AudioMixer.h
@@ -0,0 +1,192 @@
+/* //device/include/server/AudioFlinger/AudioMixer.h
+**
+** 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
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_AUDIO_MIXER_H
+#define ANDROID_AUDIO_MIXER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "AudioBufferProvider.h"
+#include "AudioResampler.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+// ----------------------------------------------------------------------------
+
+class AudioMixer
+{
+public:
+ AudioMixer(size_t frameCount, uint32_t sampleRate);
+
+ ~AudioMixer();
+
+ static const uint32_t MAX_NUM_TRACKS = 32;
+ static const uint32_t MAX_NUM_CHANNELS = 2;
+
+ static const uint16_t UNITY_GAIN = 0x1000;
+
+ enum { // names
+
+ // track units (32 units)
+ TRACK0 = 0x1000,
+
+ // enable/disable
+ MIXING = 0x2000,
+
+ // setParameter targets
+ TRACK = 0x3000,
+ RESAMPLE = 0x3001,
+ RAMP_VOLUME = 0x3002, // ramp to new volume
+ VOLUME = 0x3003, // don't ramp
+
+ // set Parameter names
+ // for target TRACK
+ CHANNEL_COUNT = 0x4000,
+ FORMAT = 0x4001,
+ // for TARGET RESAMPLE
+ SAMPLE_RATE = 0x4100,
+ // for TARGET VOLUME (8 channels max)
+ VOLUME0 = 0x4200,
+ VOLUME1 = 0x4201,
+ };
+
+
+ int getTrackName();
+ void deleteTrackName(int name);
+
+ status_t enable(int name);
+ status_t disable(int name);
+
+ status_t setActiveTrack(int track);
+ status_t setParameter(int target, int name, int value);
+
+ status_t setBufferProvider(AudioBufferProvider* bufferProvider);
+ void process(void* output);
+
+ uint32_t trackNames() const { return mTrackNames; }
+
+private:
+
+ enum {
+ NEEDS_CHANNEL_COUNT__MASK = 0x00000003,
+ NEEDS_FORMAT__MASK = 0x000000F0,
+ NEEDS_MUTE__MASK = 0x00000100,
+ NEEDS_RESAMPLE__MASK = 0x00001000,
+ };
+
+ enum {
+ NEEDS_CHANNEL_1 = 0x00000000,
+ NEEDS_CHANNEL_2 = 0x00000001,
+
+ NEEDS_FORMAT_16 = 0x00000010,
+
+ NEEDS_MUTE_DISABLED = 0x00000000,
+ NEEDS_MUTE_ENABLED = 0x00000100,
+
+ NEEDS_RESAMPLE_DISABLED = 0x00000000,
+ NEEDS_RESAMPLE_ENABLED = 0x00001000,
+ };
+
+ static inline int32_t applyVolume(int32_t in, int32_t v) {
+ return in * v;
+ }
+
+
+ struct state_t;
+
+ typedef void (*mix_t)(state_t* state, void* output);
+
+ static const int BLOCKSIZE = 16; // 4 cache lines
+
+ struct track_t {
+ uint32_t needs;
+
+ union {
+ int16_t volume[2]; // [0]3.12 fixed point
+ int32_t volumeRL;
+ };
+
+ int32_t prevVolume[2];
+
+ int32_t volumeInc[2];
+
+ uint16_t reserved;
+
+ uint8_t channelCount : 4;
+ uint8_t enabled : 1;
+ uint8_t reserved0 : 3;
+ uint8_t format;
+
+ AudioBufferProvider* bufferProvider;
+ mutable AudioBufferProvider::Buffer buffer;
+
+ void (*hook)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp);
+ void const* in; // current location in buffer
+
+ AudioResampler* resampler;
+ uint32_t sampleRate;
+
+ bool setResampler(uint32_t sampleRate, uint32_t devSampleRate);
+ bool doesResample() const;
+ void adjustVolumeRamp();
+ };
+
+ // pad to 32-bytes to fill cache line
+ struct state_t {
+ uint32_t enabledTracks;
+ uint32_t needsChanged;
+ size_t frameCount;
+ mix_t hook;
+ int32_t *outputTemp;
+ int32_t *resampleTemp;
+ int32_t reserved[2];
+ track_t tracks[32]; __attribute__((aligned(32)));
+ };
+
+ int mActiveTrack;
+ uint32_t mTrackNames;
+ const uint32_t mSampleRate;
+
+ state_t mState __attribute__((aligned(32)));
+
+ void invalidateState(uint32_t mask);
+
+ static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
+ static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
+ static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp);
+ static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
+ static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
+ static void ditherAndClamp(int32_t* out, int32_t const *sums, size_t c);
+
+ static void process__validate(state_t* state, void* output);
+ static void process__nop(state_t* state, void* output);
+ static void process__genericNoResampling(state_t* state, void* output);
+ static void process__genericResampling(state_t* state, void* output);
+ static void process__OneTrack16BitsStereoNoResampling(state_t* state, void* output);
+ static void process__TwoTracks16BitsStereoNoResampling(state_t* state, void* output);
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_AUDIO_MIXER_H
diff --git a/libs/audioflinger/AudioResampler.cpp b/libs/audioflinger/AudioResampler.cpp
new file mode 100644
index 0000000..c93ead3
--- /dev/null
+++ b/libs/audioflinger/AudioResampler.cpp
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 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
+ *
+ * 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 <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 {
+// ----------------------------------------------------------------------------
+
+class AudioResamplerOrder1 : public AudioResampler {
+public:
+ AudioResamplerOrder1(int bitDepth, int inChannelCount, int32_t sampleRate) :
+ AudioResampler(bitDepth, inChannelCount, sampleRate), mX0L(0), mX0R(0) {
+ }
+ virtual void resample(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider);
+private:
+ // number of bits used in interpolation multiply - 15 bits avoids overflow
+ static const int kNumInterpBits = 15;
+
+ // bits to shift the phase fraction down to avoid overflow
+ static const int kPreInterpShift = kNumPhaseBits - kNumInterpBits;
+
+ void init() {}
+ void resampleMono16(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider);
+ void resampleStereo16(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider);
+ static inline int32_t Interp(int32_t x0, int32_t x1, uint32_t f) {
+ return x0 + (((x1 - x0) * (int32_t)(f >> kPreInterpShift)) >> kNumInterpBits);
+ }
+ static inline void Advance(size_t* index, uint32_t* frac, uint32_t inc) {
+ *frac += inc;
+ *index += (size_t)(*frac >> kNumPhaseBits);
+ *frac &= kPhaseMask;
+ }
+ int mX0L;
+ int mX0R;
+};
+
+// ----------------------------------------------------------------------------
+AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount,
+ int32_t sampleRate, int quality) {
+
+ // can only create low quality resample now
+ AudioResampler* resampler;
+
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("af.resampler.quality", value, 0)) {
+ quality = atoi(value);
+ LOGD("forcing AudioResampler quality to %d", quality);
+ }
+
+ if (quality == DEFAULT)
+ quality = LOW_QUALITY;
+
+ switch (quality) {
+ default:
+ case LOW_QUALITY:
+ resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate);
+ break;
+ case MED_QUALITY:
+ resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate);
+ break;
+ case HIGH_QUALITY:
+ resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate);
+ break;
+ }
+
+ // initialize resampler
+ resampler->init();
+ return resampler;
+}
+
+AudioResampler::AudioResampler(int bitDepth, int inChannelCount,
+ int32_t sampleRate) :
+ mBitDepth(bitDepth), mChannelCount(inChannelCount),
+ mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0),
+ mPhaseFraction(0) {
+ // sanity check on format
+ if ((bitDepth != 16) ||(inChannelCount < 1) || (inChannelCount > 2)) {
+ LOGE("Unsupported sample format, %d bits, %d channels", bitDepth,
+ inChannelCount);
+ // LOG_ASSERT(0);
+ }
+
+ // initialize common members
+ mVolume[0] = mVolume[1] = 0;
+ mBuffer.raw = NULL;
+
+ // save format for quick lookup
+ if (inChannelCount == 1) {
+ mFormat = MONO_16_BIT;
+ } else {
+ mFormat = STEREO_16_BIT;
+ }
+}
+
+AudioResampler::~AudioResampler() {
+}
+
+void AudioResampler::setSampleRate(int32_t inSampleRate) {
+ mInSampleRate = inSampleRate;
+ mPhaseIncrement = (uint32_t)((kPhaseMultiplier * inSampleRate) / mSampleRate);
+}
+
+void AudioResampler::setVolume(int16_t left, int16_t right) {
+ // TODO: Implement anti-zipper filter
+ mVolume[0] = left;
+ mVolume[1] = right;
+}
+
+// ----------------------------------------------------------------------------
+
+void AudioResamplerOrder1::resample(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider) {
+
+ // should never happen, but we overflow if it does
+ // LOG_ASSERT(outFrameCount < 32767);
+
+ // select the appropriate resampler
+ switch (mChannelCount) {
+ case 1:
+ resampleMono16(out, outFrameCount, provider);
+ break;
+ case 2:
+ resampleStereo16(out, outFrameCount, provider);
+ break;
+ }
+}
+
+void AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider) {
+
+ int32_t vl = mVolume[0];
+ int32_t vr = mVolume[1];
+
+ size_t inputIndex = mInputIndex;
+ uint32_t phaseFraction = mPhaseFraction;
+ uint32_t phaseIncrement = mPhaseIncrement;
+ size_t outputIndex = 0;
+ size_t outputSampleCount = outFrameCount * 2;
+
+ // 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) {
+ provider->getNextBuffer(&mBuffer);
+ if (mBuffer.raw == NULL)
+ break;
+ // LOGE("New buffer fetched: %d frames\n", mBuffer.frameCount);
+ }
+ int16_t *in = mBuffer.i16;
+
+ // handle boundary case
+ while (inputIndex == 0) {
+ // LOGE("boundary case\n");
+ out[outputIndex++] += vl * Interp(mX0L, in[0], phaseFraction);
+ out[outputIndex++] += vr * Interp(mX0R, in[1], phaseFraction);
+ Advance(&inputIndex, &phaseFraction, phaseIncrement);
+ if (outputIndex == outputSampleCount)
+ break;
+ }
+
+ // process input samples
+ // LOGE("general case\n");
+ while (outputIndex < outputSampleCount) {
+ 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);
+
+ 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);
+ }
+ }
+
+ // LOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+
+ // save state
+ mInputIndex = inputIndex;
+ mPhaseFraction = phaseFraction;
+}
+
+void AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider) {
+
+ int32_t vl = mVolume[0];
+ int32_t vr = mVolume[1];
+
+ size_t inputIndex = mInputIndex;
+ uint32_t phaseFraction = mPhaseFraction;
+ uint32_t phaseIncrement = mPhaseIncrement;
+ size_t outputIndex = 0;
+ size_t outputSampleCount = outFrameCount * 2;
+
+ // 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) {
+ provider->getNextBuffer(&mBuffer);
+ if (mBuffer.raw == NULL)
+ break;
+ // LOGE("New buffer fetched: %d frames\n", mBuffer.frameCount);
+ }
+ int16_t *in = mBuffer.i16;
+
+ // handle boundary case
+ while (inputIndex == 0) {
+ // LOGE("boundary case\n");
+ int32_t sample = Interp(mX0L, in[0], phaseFraction);
+ out[outputIndex++] += vl * sample;
+ out[outputIndex++] += vr * sample;
+ Advance(&inputIndex, &phaseFraction, phaseIncrement);
+ if (outputIndex == outputSampleCount)
+ break;
+ }
+
+ // process input samples
+ // LOGE("general case\n");
+ while (outputIndex < outputSampleCount) {
+ 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);
+
+ mX0L = mBuffer.i16[mBuffer.frameCount-1];
+ provider->releaseBuffer(&mBuffer);
+
+ // verify that the releaseBuffer NULLS the buffer pointer
+ // LOG_ASSERT(mBuffer.raw == NULL);
+ }
+ }
+
+ // LOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+
+ // save state
+ mInputIndex = inputIndex;
+ mPhaseFraction = phaseFraction;
+}
+
+// ----------------------------------------------------------------------------
+}
+; // namespace android
+
diff --git a/libs/audioflinger/AudioResampler.h b/libs/audioflinger/AudioResampler.h
new file mode 100644
index 0000000..39656c0
--- /dev/null
+++ b/libs/audioflinger/AudioResampler.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_RESAMPLER_H
+#define ANDROID_AUDIO_RESAMPLER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "AudioBufferProvider.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class AudioResampler {
+public:
+ // Determines quality of SRC.
+ // LOW_QUALITY: linear interpolator (1st order)
+ // MED_QUALITY: cubic interpolator (3rd order)
+ // HIGH_QUALITY: fixed multi-tap FIR (e.g. 48KHz->44.1KHz)
+ // NOTE: high quality SRC will only be supported for
+ // certain fixed rate conversions. Sample rate cannot be
+ // changed dynamically.
+ enum src_quality {
+ DEFAULT=0,
+ LOW_QUALITY=1,
+ MED_QUALITY=2,
+ HIGH_QUALITY=3
+ };
+
+ static AudioResampler* create(int bitDepth, int inChannelCount,
+ int32_t sampleRate, int quality=DEFAULT);
+
+ virtual ~AudioResampler();
+
+ virtual void init() = 0;
+ virtual void setSampleRate(int32_t inSampleRate);
+ virtual void setVolume(int16_t left, int16_t right);
+
+ virtual void resample(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider) = 0;
+
+protected:
+ // number of bits for phase fraction - 30 bits allows nearly 2x downsampling
+ static const int kNumPhaseBits = 30;
+
+ // phase mask for fraction
+ static const uint32_t kPhaseMask = (1LU<<kNumPhaseBits)-1;
+
+ // multiplier to calculate fixed point phase increment
+ static const double kPhaseMultiplier = 1L << kNumPhaseBits;
+
+ enum format {MONO_16_BIT, STEREO_16_BIT};
+ AudioResampler(int bitDepth, int inChannelCount, int32_t sampleRate);
+
+ // prevent copying
+ AudioResampler(const AudioResampler&);
+ AudioResampler& operator=(const AudioResampler&);
+
+ int32_t mBitDepth;
+ int32_t mChannelCount;
+ int32_t mSampleRate;
+ int32_t mInSampleRate;
+ AudioBufferProvider::Buffer mBuffer;
+ union {
+ int16_t mVolume[2];
+ uint32_t mVolumeRL;
+ };
+ int16_t mTargetVolume[2];
+ format mFormat;
+ size_t mInputIndex;
+ int32_t mPhaseIncrement;
+ uint32_t mPhaseFraction;
+};
+
+// ----------------------------------------------------------------------------
+}
+; // namespace android
+
+#endif // ANDROID_AUDIO_RESAMPLER_H
diff --git a/libs/audioflinger/AudioResamplerCubic.cpp b/libs/audioflinger/AudioResamplerCubic.cpp
new file mode 100644
index 0000000..4f437bf
--- /dev/null
+++ b/libs/audioflinger/AudioResamplerCubic.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 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
+ *
+ * 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 <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include <cutils/log.h>
+
+#include "AudioResampler.h"
+#include "AudioResamplerCubic.h"
+
+#define LOG_TAG "AudioSRC"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+void AudioResamplerCubic::init() {
+ memset(&left, 0, sizeof(state));
+ memset(&right, 0, sizeof(state));
+}
+
+void AudioResamplerCubic::resample(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider) {
+
+ // should never happen, but we overflow if it does
+ // LOG_ASSERT(outFrameCount < 32767);
+
+ // select the appropriate resampler
+ switch (mChannelCount) {
+ case 1:
+ resampleMono16(out, outFrameCount, provider);
+ break;
+ case 2:
+ resampleStereo16(out, outFrameCount, provider);
+ break;
+ }
+}
+
+void AudioResamplerCubic::resampleStereo16(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider) {
+
+ int32_t vl = mVolume[0];
+ int32_t vr = mVolume[1];
+
+ size_t inputIndex = mInputIndex;
+ uint32_t phaseFraction = mPhaseFraction;
+ uint32_t phaseIncrement = mPhaseIncrement;
+ size_t outputIndex = 0;
+ size_t outputSampleCount = outFrameCount * 2;
+
+ // fetch first buffer
+ if (mBuffer.raw == NULL) {
+ provider->getNextBuffer(&mBuffer);
+ if (mBuffer.raw == NULL)
+ return;
+ // LOGW("New buffer: offset=%p, frames=%dn", mBuffer.raw, mBuffer.frameCount);
+ }
+ int16_t *in = mBuffer.i16;
+
+ while (outputIndex < outputSampleCount) {
+ int32_t sample;
+ int32_t x;
+
+ // calculate output sample
+ x = phaseFraction >> kPreInterpShift;
+ 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);
+ phaseFraction &= kPhaseMask;
+
+ // time to fetch another sample
+ while (indexIncrement--) {
+
+ inputIndex++;
+ if (inputIndex == mBuffer.frameCount) {
+ inputIndex = 0;
+ provider->releaseBuffer(&mBuffer);
+ provider->getNextBuffer(&mBuffer);
+ if (mBuffer.raw == NULL)
+ goto save_state; // ugly, but efficient
+ in = mBuffer.i16;
+ // LOGW("New buffer: offset=%p, frames=%d\n", mBuffer.raw, mBuffer.frameCount);
+ }
+
+ // advance sample state
+ advance(&left, in[inputIndex*2]);
+ advance(&right, in[inputIndex*2+1]);
+ }
+ }
+
+save_state:
+ // LOGW("Done: index=%d, fraction=%u", inputIndex, phaseFraction);
+ mInputIndex = inputIndex;
+ mPhaseFraction = phaseFraction;
+}
+
+void AudioResamplerCubic::resampleMono16(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider) {
+
+ int32_t vl = mVolume[0];
+ int32_t vr = mVolume[1];
+
+ size_t inputIndex = mInputIndex;
+ uint32_t phaseFraction = mPhaseFraction;
+ uint32_t phaseIncrement = mPhaseIncrement;
+ size_t outputIndex = 0;
+ size_t outputSampleCount = outFrameCount * 2;
+
+ // fetch first buffer
+ if (mBuffer.raw == NULL) {
+ provider->getNextBuffer(&mBuffer);
+ if (mBuffer.raw == NULL)
+ return;
+ // LOGW("New buffer: offset=%p, frames=%d\n", mBuffer.raw, mBuffer.frameCount);
+ }
+ int16_t *in = mBuffer.i16;
+
+ while (outputIndex < outputSampleCount) {
+ int32_t sample;
+ int32_t x;
+
+ // calculate output sample
+ x = phaseFraction >> kPreInterpShift;
+ sample = interp(&left, x);
+ out[outputIndex++] += vl * sample;
+ out[outputIndex++] += vr * sample;
+
+ // increment phase
+ phaseFraction += phaseIncrement;
+ uint32_t indexIncrement = (phaseFraction >> kNumPhaseBits);
+ phaseFraction &= kPhaseMask;
+
+ // time to fetch another sample
+ while (indexIncrement--) {
+
+ inputIndex++;
+ if (inputIndex == mBuffer.frameCount) {
+ inputIndex = 0;
+ provider->releaseBuffer(&mBuffer);
+ provider->getNextBuffer(&mBuffer);
+ if (mBuffer.raw == NULL)
+ goto save_state; // ugly, but efficient
+ // LOGW("New buffer: offset=%p, frames=%dn", mBuffer.raw, mBuffer.frameCount);
+ in = mBuffer.i16;
+ }
+
+ // advance sample state
+ advance(&left, in[inputIndex]);
+ }
+ }
+
+save_state:
+ // LOGW("Done: index=%d, fraction=%u", inputIndex, phaseFraction);
+ mInputIndex = inputIndex;
+ mPhaseFraction = phaseFraction;
+}
+
+// ----------------------------------------------------------------------------
+}
+; // namespace android
+
diff --git a/libs/audioflinger/AudioResamplerCubic.h b/libs/audioflinger/AudioResamplerCubic.h
new file mode 100644
index 0000000..b72b62a
--- /dev/null
+++ b/libs/audioflinger/AudioResamplerCubic.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_RESAMPLER_CUBIC_H
+#define ANDROID_AUDIO_RESAMPLER_CUBIC_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <cutils/log.h>
+
+#include "AudioResampler.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class AudioResamplerCubic : public AudioResampler {
+public:
+ AudioResamplerCubic(int bitDepth, int inChannelCount, int32_t sampleRate) :
+ AudioResampler(bitDepth, inChannelCount, sampleRate) {
+ }
+ virtual void resample(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider);
+private:
+ // number of bits used in interpolation multiply - 14 bits avoids overflow
+ static const int kNumInterpBits = 14;
+
+ // bits to shift the phase fraction down to avoid overflow
+ static const int kPreInterpShift = kNumPhaseBits - kNumInterpBits;
+ typedef struct {
+ int32_t a, b, c, y0, y1, y2, y3;
+ } state;
+ void init();
+ void resampleMono16(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider);
+ void resampleStereo16(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider);
+ static inline int32_t interp(state* p, int32_t x) {
+ return (((((p->a * x >> 14) + p->b) * x >> 14) + p->c) * x >> 14) + p->y1;
+ }
+ static inline void advance(state* p, int16_t in) {
+ p->y0 = p->y1;
+ p->y1 = p->y2;
+ p->y2 = p->y3;
+ p->y3 = in;
+ p->a = (3 * (p->y1 - p->y2) - p->y0 + p->y3) >> 1;
+ p->b = (p->y2 << 1) + p->y0 - (((5 * p->y1 + p->y3)) >> 1);
+ p->c = (p->y2 - p->y0) >> 1;
+ }
+ state left, right;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif /*ANDROID_AUDIO_RESAMPLER_CUBIC_H*/
diff --git a/libs/audioflinger/AudioResamplerSinc.cpp b/libs/audioflinger/AudioResamplerSinc.cpp
new file mode 100644
index 0000000..e710d16
--- /dev/null
+++ b/libs/audioflinger/AudioResamplerSinc.cpp
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 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
+ *
+ * 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 <string.h>
+#include "AudioResamplerSinc.h"
+
+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.
+ */
+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
+};
+
+/*
+ * These coefficients are optimized for 48KHz -> 44.1KHz (stop-band at 22.050KHz)
+ * It's possible to use the above coefficient for any down-sampling
+ * at the expense of a slower processing loop (we can interpolate
+ * 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
+};
+
+// ----------------------------------------------------------------------------
+
+static inline
+int32_t mulRL(int left, int32_t in, uint32_t vRL)
+{
+#if defined(__arm__) && !defined(__thumb__)
+ int32_t out;
+ if (left) {
+ asm( "smultb %[out], %[in], %[vRL] \n"
+ : [out]"=r"(out)
+ : [in]"%r"(in), [vRL]"r"(vRL)
+ : );
+ } else {
+ asm( "smultt %[out], %[in], %[vRL] \n"
+ : [out]"=r"(out)
+ : [in]"%r"(in), [vRL]"r"(vRL)
+ : );
+ }
+ return out;
+#else
+ if (left) {
+ return int16_t(in>>16) * int16_t(vRL&0xFFFF);
+ } else {
+ return int16_t(in>>16) * int16_t(vRL>>16);
+ }
+#endif
+}
+
+static inline
+int32_t mulAdd(int16_t in, int32_t v, int32_t a)
+{
+#if defined(__arm__) && !defined(__thumb__)
+ int32_t out;
+ asm( "smlawb %[out], %[v], %[in], %[a] \n"
+ : [out]"=r"(out)
+ : [in]"%r"(in), [v]"r"(v), [a]"r"(a)
+ : );
+ return out;
+#else
+ return a + ((in * int32_t(v))>>16);
+#endif
+}
+
+static inline
+int32_t mulAddRL(int left, uint32_t inRL, int32_t v, int32_t a)
+{
+#if defined(__arm__) && !defined(__thumb__)
+ int32_t out;
+ if (left) {
+ asm( "smlawb %[out], %[v], %[inRL], %[a] \n"
+ : [out]"=r"(out)
+ : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a)
+ : );
+ } else {
+ asm( "smlawt %[out], %[v], %[inRL], %[a] \n"
+ : [out]"=r"(out)
+ : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a)
+ : );
+ }
+ return out;
+#else
+ if (left) {
+ return a + ((int16_t(inRL&0xFFFF) * int32_t(v))>>16);
+ } else {
+ return a + ((int16_t(inRL>>16) * int32_t(v))>>16);
+ }
+#endif
+}
+
+// ----------------------------------------------------------------------------
+
+AudioResamplerSinc::AudioResamplerSinc(int bitDepth,
+ 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
+ *
+ */
+
+ 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;
+}
+
+void AudioResamplerSinc::init() {
+}
+
+void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider)
+{
+ mFirCoefs = (mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown;
+
+ // select the appropriate resampler
+ switch (mChannelCount) {
+ case 1:
+ resample<1>(out, outFrameCount, provider);
+ break;
+ case 2:
+ resample<2>(out, outFrameCount, provider);
+ break;
+ }
+}
+
+
+template<int CHANNELS>
+void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider)
+{
+ int16_t* impulse = mImpulse;
+ uint32_t vRL = mVolumeRL;
+ size_t inputIndex = mInputIndex;
+ uint32_t phaseFraction = mPhaseFraction;
+ uint32_t phaseIncrement = mPhaseIncrement;
+ size_t outputIndex = 0;
+ size_t outputSampleCount = outFrameCount * 2;
+
+ AudioBufferProvider::Buffer& buffer(mBuffer);
+ while (outputIndex < outputSampleCount) {
+ // buffer is empty, fetch a new one
+ if (buffer.raw == NULL) {
+ provider->getNextBuffer(&buffer);
+ if (buffer.raw == NULL)
+ break;
+ const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
+ if (phaseIndex) {
+ read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+ }
+ }
+ int16_t *in = buffer.i16;
+ 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];
+
+ // handle boundary case
+ 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);
+
+ phaseFraction += phaseIncrement;
+ const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
+ if (phaseIndex) {
+ inputIndex += phaseIndex;
+ if (inputIndex >= frameCount)
+ break;
+ read<CHANNELS>(impulse, phaseFraction, in, inputIndex);
+ }
+ }
+
+ // if done with buffer, save samples
+ if (inputIndex >= frameCount) {
+ inputIndex -= frameCount;
+ provider->releaseBuffer(&buffer);
+ }
+ }
+
+ mImpulse = impulse;
+ mInputIndex = inputIndex;
+ mPhaseFraction = phaseFraction;
+}
+
+template<int CHANNELS>
+void AudioResamplerSinc::read(
+ 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];
+ }
+}
+
+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;
+ interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
+ interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
+ 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;
+ 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 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);
+ }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/libs/audioflinger/AudioResamplerSinc.h b/libs/audioflinger/AudioResamplerSinc.h
new file mode 100644
index 0000000..89b9577
--- /dev/null
+++ b/libs/audioflinger/AudioResamplerSinc.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_RESAMPLER_SINC_H
+#define ANDROID_AUDIO_RESAMPLER_SINC_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <cutils/log.h>
+
+#include "AudioResampler.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class AudioResamplerSinc : public AudioResampler {
+public:
+ AudioResamplerSinc(int bitDepth, int inChannelCount, int32_t sampleRate);
+
+ ~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);
+
+ template<int CHANNELS>
+ inline void filterCoefficient(
+ int32_t& l, int32_t& r, uint32_t phase, int16_t const *samples);
+
+ template<int CHANNELS>
+ inline void interpolate(
+ int32_t& l, int32_t& r,
+ int32_t const* coefs, int16_t lerp, int16_t const* samples);
+
+ template<int CHANNELS>
+ inline void read(int16_t*& impulse, uint32_t& phaseFraction,
+ 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[];
+
+ // ----------------------------------------------------------------------------
+ static const int32_t RESAMPLE_FIR_NUM_COEF = 8;
+ 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;
+
+ // 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;
+
+ // number of zero-crossing on each side
+ static const unsigned int halfNumCoefs = RESAMPLE_FIR_NUM_COEF;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif /*ANDROID_AUDIO_RESAMPLER_SINC_H*/