summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:43 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:43 -0800
commite09fd9e819c23dc90bca68375645e15544861330 (patch)
tree9a9fdadd1301625f875a3c126c986c79e3363ac4 /libs
parent7c1b96a165f970a09ed239bb4fb3f1b0d8f2a407 (diff)
downloadframeworks_native-e09fd9e819c23dc90bca68375645e15544861330.zip
frameworks_native-e09fd9e819c23dc90bca68375645e15544861330.tar.gz
frameworks_native-e09fd9e819c23dc90bca68375645e15544861330.tar.bz2
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'libs')
-rw-r--r--libs/audioflinger/A2dpAudioInterface.cpp186
-rw-r--r--libs/audioflinger/A2dpAudioInterface.h107
-rw-r--r--libs/audioflinger/Android.mk7
-rw-r--r--libs/audioflinger/AudioDumpInterface.cpp49
-rw-r--r--libs/audioflinger/AudioDumpInterface.h53
-rw-r--r--libs/audioflinger/AudioFlinger.cpp710
-rw-r--r--libs/audioflinger/AudioFlinger.h101
-rw-r--r--libs/audioflinger/AudioHardwareGeneric.cpp46
-rw-r--r--libs/audioflinger/AudioHardwareGeneric.h30
-rw-r--r--libs/audioflinger/AudioHardwareInterface.cpp59
-rw-r--r--libs/audioflinger/AudioHardwareStub.cpp36
-rw-r--r--libs/audioflinger/AudioHardwareStub.h28
-rw-r--r--libs/audioflinger/AudioMixer.cpp278
-rw-r--r--libs/audioflinger/AudioMixer.h18
-rw-r--r--libs/audioflinger/AudioResampler.cpp350
-rw-r--r--libs/audioflinger/AudioResamplerCubic.cpp18
-rw-r--r--libs/audioflinger/AudioResamplerSinc.cpp292
-rw-r--r--libs/audioflinger/AudioResamplerSinc.h23
-rw-r--r--libs/surfaceflinger/Android.mk1
-rw-r--r--libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp46
-rw-r--r--libs/surfaceflinger/DisplayHardware/DisplayHardware.h10
-rw-r--r--libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp20
-rw-r--r--libs/surfaceflinger/GPUHardware/GPUHardware.cpp608
-rw-r--r--libs/surfaceflinger/GPUHardware/GPUHardware.h77
-rw-r--r--libs/surfaceflinger/Layer.cpp33
-rw-r--r--libs/surfaceflinger/LayerBase.cpp37
-rw-r--r--libs/surfaceflinger/LayerBase.h14
-rw-r--r--libs/surfaceflinger/LayerBlur.cpp10
-rw-r--r--libs/surfaceflinger/LayerBuffer.cpp52
-rw-r--r--libs/surfaceflinger/LayerBuffer.h6
-rw-r--r--libs/surfaceflinger/LayerDim.cpp4
-rw-r--r--libs/surfaceflinger/SurfaceFlinger.cpp79
-rw-r--r--libs/surfaceflinger/SurfaceFlinger.h9
-rw-r--r--libs/surfaceflinger/VRamHeap.cpp81
-rw-r--r--libs/surfaceflinger/VRamHeap.h22
-rw-r--r--libs/ui/Android.mk3
-rw-r--r--libs/ui/BlitHardware.cpp446
-rw-r--r--libs/ui/Camera.cpp119
-rw-r--r--libs/ui/EGLDisplaySurface.cpp35
-rw-r--r--libs/ui/EGLNativeWindowSurface.cpp7
-rw-r--r--libs/ui/EventHub.cpp13
-rw-r--r--libs/ui/ICamera.cpp82
-rw-r--r--libs/ui/ICameraClient.cpp16
-rw-r--r--libs/ui/IOverlay.cpp87
-rw-r--r--libs/ui/ISurface.cpp22
-rw-r--r--libs/ui/ISurfaceFlingerClient.cpp4
-rw-r--r--libs/ui/Overlay.cpp145
-rw-r--r--libs/ui/Surface.cpp7
-rw-r--r--libs/ui/Time.cpp4
-rw-r--r--libs/utils/Android.mk8
-rw-r--r--libs/utils/CallStack.cpp58
-rw-r--r--libs/utils/IPCThreadState.cpp27
-rw-r--r--libs/utils/LogSocket.cpp2
-rw-r--r--libs/utils/MemoryDealer.cpp22
-rw-r--r--libs/utils/MemoryHeapPmem.cpp54
-rw-r--r--libs/utils/ResourceTypes.cpp41
-rw-r--r--libs/utils/futex_synchro.c6
57 files changed, 2871 insertions, 1837 deletions
diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/libs/audioflinger/A2dpAudioInterface.cpp
new file mode 100644
index 0000000..d54795c
--- /dev/null
+++ b/libs/audioflinger/A2dpAudioInterface.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <math.h>
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "A2dpAudioInterface"
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "A2dpAudioInterface.h"
+#include "audio/liba2dp.h"
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+A2dpAudioInterface::A2dpAudioInterface() :
+ mOutput(0)
+{
+}
+
+A2dpAudioInterface::~A2dpAudioInterface()
+{
+ delete mOutput;
+}
+
+status_t A2dpAudioInterface::initCheck()
+{
+ return 0;
+}
+
+AudioStreamOut* A2dpAudioInterface::openOutputStream(
+ int format, int channelCount, uint32_t sampleRate, status_t *status)
+{
+ LOGD("A2dpAudioInterface::openOutputStream %d, %d, %d\n", format, channelCount, sampleRate);
+ Mutex::Autolock lock(mLock);
+ status_t err = 0;
+
+ // only one output stream allowed
+ if (mOutput) {
+ if (status)
+ *status = -1;
+ return NULL;
+ }
+
+ // create new output stream
+ A2dpAudioStreamOut* out = new A2dpAudioStreamOut();
+ if ((err = out->set(format, channelCount, sampleRate)) == NO_ERROR) {
+ mOutput = out;
+ } else {
+ delete out;
+ }
+
+ if (status)
+ *status = err;
+ return mOutput;
+}
+
+AudioStreamIn* A2dpAudioInterface::openInputStream(
+ int format, int channelCount, uint32_t sampleRate, status_t *status)
+{
+ if (status)
+ *status = -1;
+ return NULL;
+}
+
+status_t A2dpAudioInterface::standby()
+{
+ return 0;
+}
+
+status_t A2dpAudioInterface::setMicMute(bool state)
+{
+ return 0;
+}
+
+status_t A2dpAudioInterface::getMicMute(bool* state)
+{
+ return 0;
+}
+
+status_t A2dpAudioInterface::setParameter(const char *key, const char *value)
+{
+ LOGD("setParameter %s,%s\n", key, value);
+ return 0;
+}
+
+status_t A2dpAudioInterface::setVoiceVolume(float v)
+{
+ return 0;
+}
+
+status_t A2dpAudioInterface::setMasterVolume(float v)
+{
+ return 0;
+}
+
+status_t A2dpAudioInterface::doRouting()
+{
+ return 0;
+}
+
+status_t A2dpAudioInterface::dump(int fd, const Vector<String16>& args)
+{
+ return 0;
+}
+
+// ----------------------------------------------------------------------------
+
+A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() :
+ mFd(-1), mStartCount(0), mRetryCount(0), mData(NULL),
+ mInitialized(false), mBufferRemaining(0)
+{
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::set(
+ int format, int channels, uint32_t rate)
+{
+ LOGD("A2dpAudioStreamOut::set %d, %d, %d\n", format, channels, rate);
+
+ // fix up defaults
+ if (format == 0) format = AudioSystem::PCM_16_BIT;
+ if (channels == 0) channels = channelCount();
+ if (rate == 0) rate = sampleRate();
+
+ // check values
+ if ((format != AudioSystem::PCM_16_BIT) ||
+ (channels != channelCount()) ||
+ (rate != sampleRate()))
+ return BAD_VALUE;
+
+ return NO_ERROR;
+}
+
+A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut()
+{
+ if (mData)
+ a2dp_cleanup(mData);
+}
+
+ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes)
+{
+ if (!mInitialized) {
+ int ret = a2dp_init("00:00:00:00:00:00", 44100, 2, &mData);
+ if (ret)
+ return ret;
+ mInitialized = true;
+ }
+
+ size_t remaining = bytes;
+ while (remaining > 0) {
+ int written = a2dp_write(mData, buffer, remaining);
+ remaining -= written;
+ buffer = ((char *)buffer) + written;
+ }
+
+ return bytes;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::standby()
+{
+ return 0;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::dump(int fd, const Vector<String16>& args)
+{
+ return NO_ERROR;
+}
+
+
+}; // namespace android
diff --git a/libs/audioflinger/A2dpAudioInterface.h b/libs/audioflinger/A2dpAudioInterface.h
new file mode 100644
index 0000000..03bf933
--- /dev/null
+++ b/libs/audioflinger/A2dpAudioInterface.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef A2DP_AUDIO_HARDWARE_H
+#define A2DP_AUDIO_HARDWARE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+
+#include <hardware/AudioHardwareBase.h>
+
+
+namespace android {
+
+class A2dpAudioInterface : public AudioHardwareBase
+{
+ class A2dpAudioStreamOut;
+
+public:
+ A2dpAudioInterface();
+ virtual ~A2dpAudioInterface();
+ virtual status_t initCheck();
+ virtual status_t standby();
+
+ virtual status_t setVoiceVolume(float volume);
+ virtual status_t setMasterVolume(float volume);
+
+ // mic mute
+ virtual status_t setMicMute(bool state);
+ virtual status_t getMicMute(bool* state);
+
+ // Temporary interface, do not use
+ // TODO: Replace with a more generic key:value get/set mechanism
+ virtual status_t setParameter(const char *key, const char *value);
+
+ // create I/O streams
+ virtual AudioStreamOut* openOutputStream(
+ int format=0,
+ int channelCount=0,
+ uint32_t sampleRate=0,
+ status_t *status=0);
+
+ virtual AudioStreamIn* openInputStream(
+ int format,
+ int channelCount,
+ uint32_t sampleRate,
+ status_t *status);
+
+protected:
+ virtual status_t doRouting();
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+private:
+ class A2dpAudioStreamOut : public AudioStreamOut {
+ public:
+ A2dpAudioStreamOut();
+ virtual ~A2dpAudioStreamOut();
+ status_t set(int format,
+ int channelCount,
+ uint32_t sampleRate);
+ virtual uint32_t sampleRate() const { return 44100; }
+ // must be 32-bit aligned - driver only seems to like 4800
+ virtual size_t bufferSize() const { return 5120; }
+ virtual int channelCount() const { return 2; }
+ virtual int format() const { return AudioSystem::PCM_16_BIT; }
+ virtual uint32_t latency() const { return 0; }
+ virtual status_t setVolume(float volume) { return INVALID_OPERATION; }
+ virtual ssize_t write(const void* buffer, size_t bytes);
+ status_t standby();
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ private:
+ int mFd;
+ int mStartCount;
+ int mRetryCount;
+ void* mData;
+ bool mInitialized;
+
+#define kBufferSize 50000
+ char mBuffer[kBufferSize];
+ int mBufferRemaining;
+ };
+
+ Mutex mLock;
+ A2dpAudioStreamOut* mOutput;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // A2DP_AUDIO_HARDWARE_H
diff --git a/libs/audioflinger/Android.mk b/libs/audioflinger/Android.mk
index a9cb303..d16e3e1 100644
--- a/libs/audioflinger/Android.mk
+++ b/libs/audioflinger/Android.mk
@@ -45,9 +45,12 @@ endif
LOCAL_MODULE:= libaudioflinger
-ifeq ($(TARGET_ARCH),arm) # not simulator
- LOCAL_CFLAGS += -DWITH_BLUETOOTH
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+ LOCAL_SRC_FILES += A2dpAudioInterface.cpp
+ LOCAL_SHARED_LIBRARIES += liba2dp
+ LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP
LOCAL_C_INCLUDES += $(call include-path-for, bluez-libs)
+ LOCAL_C_INCLUDES += $(call include-path-for, bluez-utils)
endif
include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/audioflinger/AudioDumpInterface.cpp b/libs/audioflinger/AudioDumpInterface.cpp
index 5ff2f18..8eee9cc 100644
--- a/libs/audioflinger/AudioDumpInterface.cpp
+++ b/libs/audioflinger/AudioDumpInterface.cpp
@@ -2,16 +2,16 @@
**
** Copyright 2008, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
@@ -28,6 +28,8 @@
namespace android {
+bool gFirst = true; // true if first write after a standby
+
// ----------------------------------------------------------------------------
AudioDumpInterface::AudioDumpInterface(AudioHardwareInterface* hw)
@@ -40,17 +42,25 @@ AudioDumpInterface::AudioDumpInterface(AudioHardwareInterface* hw)
}
+AudioDumpInterface::~AudioDumpInterface()
+{
+ if(mFinalInterface) delete mFinalInterface;
+ if(mStreamOut) delete mStreamOut;
+}
+
+
status_t AudioDumpInterface::standby()
{
if(mStreamOut) mStreamOut->Close();
+ gFirst = true;
return mFinalInterface->standby();
}
AudioStreamOut* AudioDumpInterface::openOutputStream(
- int format, int channelCount, uint32_t sampleRate)
+ int format, int channelCount, uint32_t sampleRate, status_t *status)
{
- AudioStreamOut* outFinal = mFinalInterface->openOutputStream(format, channelCount, sampleRate);
+ AudioStreamOut* outFinal = mFinalInterface->openOutputStream(format, channelCount, sampleRate, status);
if(outFinal) {
mStreamOut = new AudioStreamOutDump(outFinal);
@@ -69,13 +79,26 @@ AudioStreamOutDump::AudioStreamOutDump( AudioStreamOut* finalStream)
mOutFile = 0;
}
+
+AudioStreamOutDump::~AudioStreamOutDump()
+{
+ Close();
+ delete mFinalStream;
+}
+
ssize_t AudioStreamOutDump::write(const void* buffer, size_t bytes)
{
ssize_t ret;
-
+
ret = mFinalStream->write(buffer, bytes);
- if(!mOutFile) {
- mOutFile = fopen(FLINGER_DUMP_NAME, "ab");
+ if(!mOutFile && gFirst) {
+ gFirst = false;
+ // check if dump file exist
+ mOutFile = fopen(FLINGER_DUMP_NAME, "r");
+ if(mOutFile) {
+ fclose(mOutFile);
+ mOutFile = fopen(FLINGER_DUMP_NAME, "ab");
+ }
}
if (mOutFile) {
fwrite(buffer, bytes, 1, mOutFile);
diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h
index 732b97d..a65e56a 100644
--- a/libs/audioflinger/AudioDumpInterface.h
+++ b/libs/audioflinger/AudioDumpInterface.h
@@ -2,16 +2,16 @@
**
** Copyright 2008, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
@@ -21,33 +21,35 @@
#include <stdint.h>
#include <sys/types.h>
-#include <hardware/AudioHardwareInterface.h>
+#include <hardware/AudioHardwareBase.h>
namespace android {
-#define FLINGER_DUMP_NAME "/tmp/FlingerOut.pcm" // name of file used for dump
+#define FLINGER_DUMP_NAME "/data/FlingerOut.pcm" // name of file used for dump
class AudioStreamOutDump : public AudioStreamOut {
public:
AudioStreamOutDump( AudioStreamOut* FinalStream);
+ ~AudioStreamOutDump();
virtual ssize_t write(const void* buffer, size_t bytes);
-
+
virtual uint32_t sampleRate() const { return mFinalStream->sampleRate(); }
virtual size_t bufferSize() const { return mFinalStream->bufferSize(); }
virtual int channelCount() const { return mFinalStream->channelCount(); }
virtual int format() const { return mFinalStream->format(); }
+ virtual uint32_t latency() const { return mFinalStream->latency(); }
virtual status_t setVolume(float volume)
{ return mFinalStream->setVolume(volume); }
virtual status_t dump(int fd, const Vector<String16>& args) { return mFinalStream->dump(fd, args); }
void Close(void);
private:
- AudioStreamOut *mFinalStream;
- FILE *mOutFile; // output file
+ AudioStreamOut *mFinalStream;
+ FILE *mOutFile; // output file
};
-class AudioDumpInterface : public AudioHardwareInterface
+class AudioDumpInterface : public AudioHardwareBase
{
public:
@@ -56,10 +58,10 @@ public:
virtual AudioStreamOut* openOutputStream(
int format=0,
int channelCount=0,
- uint32_t sampleRate=0);
+ uint32_t sampleRate=0,
+ status_t *status=0);
+ virtual ~AudioDumpInterface();
- virtual ~AudioDumpInterface()
- {delete mFinalInterface;}
virtual status_t initCheck()
{return mFinalInterface->initCheck();}
virtual status_t setVoiceVolume(float volume)
@@ -67,13 +69,6 @@ public:
virtual status_t setMasterVolume(float volume)
{return mFinalInterface->setMasterVolume(volume);}
- virtual status_t setRouting(int mode, uint32_t routes)
- {return mFinalInterface->setRouting(mode, routes);}
- virtual status_t getRouting(int mode, uint32_t* routes)
- {return mFinalInterface->getRouting(mode, routes);}
- virtual status_t getMode(int* mode)
- {return mFinalInterface->getMode(mode);}
-
// mic mute
virtual status_t setMicMute(bool state)
{return mFinalInterface->setMicMute(state);}
@@ -83,17 +78,17 @@ public:
virtual status_t setParameter(const char* key, const char* value)
{return mFinalInterface->setParameter(key, value);}
- virtual AudioStreamIn* openInputStream( int format, int channelCount, uint32_t sampleRate)
- {return mFinalInterface->openInputStream( format, channelCount, sampleRate);}
+ virtual AudioStreamIn* openInputStream( int format, int channelCount, uint32_t sampleRate, status_t *status)
+ {return mFinalInterface->openInputStream( format, channelCount, sampleRate, status);}
virtual status_t dump(int fd, const Vector<String16>& args) { return mFinalInterface->dumpState(fd, args); }
protected:
- virtual status_t doRouting() {return 0;}
-
+ virtual status_t doRouting() {return mFinalInterface->setRouting(mMode, mRoutes[mMode]);}
+
AudioHardwareInterface *mFinalInterface;
AudioStreamOutDump *mStreamOut;
-
+
};
}; // namespace android
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index fb21629..53b18ad 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -31,6 +31,8 @@
#include <utils/String16.h>
#include <utils/threads.h>
+#include <cutils/properties.h>
+
#include <media/AudioTrack.h>
#include <media/AudioRecord.h>
@@ -41,9 +43,13 @@
#include "AudioMixer.h"
#include "AudioFlinger.h"
+#ifdef WITH_A2DP
+#include "A2dpAudioInterface.h"
+#endif
+
namespace android {
-static const nsecs_t kStandbyTimeInNsecs = seconds(3);
+//static const nsecs_t kStandbyTimeInNsecs = seconds(3);
static const unsigned long kBufferRecoveryInUsecs = 2000;
static const unsigned long kMaxBufferRecoveryInUsecs = 20000;
static const float MAX_GAIN = 4096.0f;
@@ -93,8 +99,9 @@ static bool settingsAllowed() {
AudioFlinger::AudioFlinger()
: BnAudioFlinger(), Thread(false),
- mMasterVolume(0), mMasterMute(true),
- mAudioMixer(0), mAudioHardware(0), mOutput(0), mAudioRecordThread(0),
+ mMasterVolume(0), mMasterMute(true), mHardwareAudioMixer(0), mA2dpAudioMixer(0),
+ mAudioMixer(0), mAudioHardware(0), mA2dpAudioInterface(0),
+ mHardwareOutput(0), mA2dpOutput(0), mOutput(0), mAudioRecordThread(0),
mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0),
mMixBuffer(0), mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0),
mStandby(false), mInWrite(false)
@@ -105,17 +112,14 @@ AudioFlinger::AudioFlinger()
if (mAudioHardware->initCheck() == NO_ERROR) {
// open 16-bit output stream for s/w mixer
mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
- mOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT);
+ status_t status;
+ mHardwareOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
mHardwareStatus = AUDIO_HW_IDLE;
- if (mOutput) {
- mSampleRate = mOutput->sampleRate();
- mChannelCount = mOutput->channelCount();
- mFormat = mOutput->format();
- mMixBufferSize = mOutput->bufferSize();
- mFrameCount = mMixBufferSize / mChannelCount / sizeof(int16_t);
- mMixBuffer = new int16_t[mFrameCount * mChannelCount];
- memset(mMixBuffer, 0, mMixBufferSize);
- mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
+ if (mHardwareOutput) {
+ mSampleRate = mHardwareOutput->sampleRate();
+ mHardwareAudioMixer = new AudioMixer(getOutputFrameCount(mHardwareOutput), mSampleRate);
+ setOutput(mHardwareOutput);
+
// FIXME - this should come from settings
setMasterVolume(1.0f);
setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
@@ -124,20 +128,87 @@ AudioFlinger::AudioFlinger()
setMode(AudioSystem::MODE_NORMAL);
mMasterMute = false;
} else {
- LOGE("Failed to initialize output stream");
+ LOGE("Failed to initialize output stream, status: %d", status);
}
- } else {
+
+#ifdef WITH_A2DP
+ // Create A2DP interface
+ mA2dpAudioInterface = new A2dpAudioInterface();
+ mA2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
+ mA2dpAudioMixer = new AudioMixer(getOutputFrameCount(mA2dpOutput), mA2dpOutput->sampleRate());
+
+ // create a buffer big enough for both hardware and A2DP audio output.
+ size_t hwFrameCount = getOutputFrameCount(mHardwareOutput);
+ size_t a2dpFrameCount = getOutputFrameCount(mA2dpOutput);
+ size_t frameCount = (hwFrameCount > a2dpFrameCount ? hwFrameCount : a2dpFrameCount);
+#else
+ size_t frameCount = getOutputFrameCount(mHardwareOutput);
+#endif
+ // FIXME - Current mixer implementation only supports stereo output: Always
+ // Allocate a stereo buffer even if HW output is mono.
+ mMixBuffer = new int16_t[frameCount * 2];
+ memset(mMixBuffer, 0, frameCount * 2 * sizeof(int16_t));
+
+ // Start record thread
+ mAudioRecordThread = new AudioRecordThread(mAudioHardware);
+ if (mAudioRecordThread != 0) {
+ mAudioRecordThread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO);
+ }
+ } else {
LOGE("Couldn't even initialize the stubbed audio hardware!");
}
+
+ char value[PROPERTY_VALUE_MAX];
+ // FIXME: What property should this be???
+ property_get("ro.audio.silent", value, "0");
+ if (atoi(value)) {
+ LOGD("Silence is golden");
+ mMasterMute = true;
+ }
}
AudioFlinger::~AudioFlinger()
{
+ if (mAudioRecordThread != 0) {
+ mAudioRecordThread->exit();
+ mAudioRecordThread.clear();
+ }
delete mOutput;
+ delete mA2dpOutput;
delete mAudioHardware;
+ delete mA2dpAudioInterface;
delete [] mMixBuffer;
- delete mAudioMixer;
- mAudioRecordThread.clear();
+ delete mHardwareAudioMixer;
+ delete mA2dpAudioMixer;
+}
+
+void AudioFlinger::setOutput(AudioStreamOut* output)
+{
+ // lock on mOutputLock to prevent threadLoop() from starving us
+ Mutex::Autolock _l2(mOutputLock);
+
+ // to synchronize with threadLoop()
+ Mutex::Autolock _l(mLock);
+
+ if (mOutput != output) {
+ mSampleRate = output->sampleRate();
+ mChannelCount = output->channelCount();
+
+ // FIXME - Current mixer implementation only supports stereo output
+ if (mChannelCount == 1) {
+ LOGE("Invalid audio hardware channel count");
+ }
+ mFormat = output->format();
+ mFrameCount = getOutputFrameCount(output);
+
+ mAudioMixer = (output == mA2dpOutput ? mA2dpAudioMixer : mHardwareAudioMixer);
+ mOutput = output;
+ }
+}
+
+size_t AudioFlinger::getOutputFrameCount(AudioStreamOut* output)
+{
+ return output->bufferSize() / output->channelCount() / sizeof(int16_t);
}
status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
@@ -201,8 +272,8 @@ status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
-
- snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", audioMixer().trackNames());
+
+ snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", audioMixer()->trackNames());
result.append(buffer);
snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
result.append(buffer);
@@ -254,17 +325,26 @@ status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
// Thread virtuals
bool AudioFlinger::threadLoop()
{
- nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
unsigned long sleepTime = kBufferRecoveryInUsecs;
- const size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t);
int16_t* curBuf = mMixBuffer;
Vector< sp<Track> > tracksToRemove;
- size_t enabledTracks;
+ size_t enabledTracks = 0;
nsecs_t standbyTime = systemTime();
+ AudioMixer* mixer = 0;
+ size_t frameCount = 0;
+ int channelCount = 0;
+ uint32_t sampleRate = 0;
+ AudioStreamOut* output = 0;
do {
enabledTracks = 0;
- { // scope for the lock
+ { // scope for the mLock
+
+ // locking briefly on the secondary mOutputLock is necessary to avoid
+ // having this thread starve the thread that called setOutput()
+ mOutputLock.lock();
+ mOutputLock.unlock();
+
Mutex::Autolock _l(mLock);
const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
@@ -286,6 +366,15 @@ bool AudioFlinger::threadLoop()
continue;
}
+ // get active mixer and output parameter while the lock is held and keep them
+ // consistent till the next loop.
+
+ mixer = audioMixer();
+ frameCount = mFrameCount;
+ channelCount = mChannelCount;
+ sampleRate = mSampleRate;
+ output = mOutput;
+
// find out which tracks need to be processed
size_t count = activeTracks.size();
for (size_t i=0 ; i<count ; i++) {
@@ -294,13 +383,11 @@ bool AudioFlinger::threadLoop()
Track* const track = t.get();
audio_track_cblk_t* cblk = track->cblk();
- uint32_t u = cblk->user;
- uint32_t s = cblk->server;
// The first time a track is added we wait
// for all its buffers to be filled before processing it
- audioMixer().setActiveTrack(track->name());
- if ((u > s) && (track->isReady(u, s) || track->isStopped()) &&
+ mixer->setActiveTrack(track->name());
+ if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
!track->isPaused())
{
//LOGD("u=%08x, s=%08x [OK]", u, s);
@@ -325,9 +412,8 @@ bool AudioFlinger::threadLoop()
}
// XXX: these things DON'T need to be done each time
- AudioMixer& mixer(audioMixer());
- mixer.setBufferProvider(track);
- mixer.enable(AudioMixer::MIXING);
+ mixer->setBufferProvider(track);
+ mixer->enable(AudioMixer::MIXING);
int param;
if ( track->mFillingUpStatus == Track::FS_FILLED) {
@@ -342,15 +428,15 @@ bool AudioFlinger::threadLoop()
} else {
param = AudioMixer::RAMP_VOLUME;
}
- mixer.setParameter(param, AudioMixer::VOLUME0, left);
- mixer.setParameter(param, AudioMixer::VOLUME1, right);
- mixer.setParameter(
+ mixer->setParameter(param, AudioMixer::VOLUME0, left);
+ mixer->setParameter(param, AudioMixer::VOLUME1, right);
+ mixer->setParameter(
AudioMixer::TRACK,
AudioMixer::FORMAT, track->format());
- mixer.setParameter(
+ mixer->setParameter(
AudioMixer::TRACK,
AudioMixer::CHANNEL_COUNT, track->channelCount());
- mixer.setParameter(
+ mixer->setParameter(
AudioMixer::RESAMPLE,
AudioMixer::SAMPLE_RATE,
int(cblk->sampleRate));
@@ -361,8 +447,7 @@ bool AudioFlinger::threadLoop()
} else {
//LOGD("u=%08x, s=%08x [NOT READY]", u, s);
if (track->isStopped()) {
- track->mFillingUpStatus = Track::FS_FILLING;
- track->mFlags = 0;
+ track->reset();
}
if (track->isTerminated() || track->isStopped() || track->isPaused()) {
// We have consumed all the buffers of this track.
@@ -378,7 +463,7 @@ bool AudioFlinger::threadLoop()
}
}
// LOGV("disable(%d)", track->name());
- audioMixer().disable(AudioMixer::MIXING);
+ mixer->disable(AudioMixer::MIXING);
}
}
@@ -390,26 +475,27 @@ bool AudioFlinger::threadLoop()
mActiveTracks.remove(track);
if (track->isTerminated()) {
mTracks.remove(track);
- audioMixer().deleteTrackName(track->mName);
+ mixer->deleteTrackName(track->mName);
}
}
- }
- }
-
+ }
+ }
if (LIKELY(enabledTracks)) {
// mix buffers...
- audioMixer().process(curBuf);
+ mixer->process(curBuf);
// output audio to hardware
mLastWriteTime = systemTime();
mInWrite = true;
- mOutput->write(curBuf, mixBufferSize);
+ size_t mixBufferSize = frameCount*channelCount*sizeof(int16_t);
+ output->write(curBuf, mixBufferSize);
mNumWrites++;
mInWrite = false;
mStandby = false;
nsecs_t temp = systemTime();
standbyTime = temp + kStandbyTimeInNsecs;
nsecs_t delta = temp - mLastWriteTime;
+ nsecs_t maxPeriod = seconds(frameCount) / sampleRate * 2;
if (delta > maxPeriod) {
LOGW("write blocked for %llu msecs", ns2ms(delta));
mNumDelayedWrites++;
@@ -458,43 +544,60 @@ sp<IAudioTrack> AudioFlinger::createTrack(
uint32_t sampleRate,
int format,
int channelCount,
- int bufferCount,
- uint32_t flags)
+ int frameCount,
+ uint32_t flags,
+ const sp<IMemory>& sharedBuffer,
+ status_t *status)
{
+ sp<Track> track;
+ sp<TrackHandle> trackHandle;
+ sp<Client> client;
+ wp<Client> wclient;
+ status_t lStatus;
+
if (streamType >= AudioTrack::NUM_STREAM_TYPES) {
LOGE("invalid stream type");
- return NULL;
+ lStatus = BAD_VALUE;
+ goto Exit;
}
- if (sampleRate > MAX_SAMPLE_RATE) {
+ // Resampler implementation limits input sampling rate to 2 x output sampling rate.
+ if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) {
LOGE("Sample rate out of range: %d", sampleRate);
- return NULL;
+ lStatus = BAD_VALUE;
+ goto Exit;
}
- sp<Track> track;
- sp<TrackHandle> trackHandle;
- Mutex::Autolock _l(mLock);
+ {
+ Mutex::Autolock _l(mLock);
- if (mSampleRate == 0) {
- LOGE("Audio driver not initialized.");
- return trackHandle;
- }
+ if (mSampleRate == 0) {
+ LOGE("Audio driver not initialized.");
+ lStatus = NO_INIT;
+ goto Exit;
+ }
- sp<Client> client;
- wp<Client> wclient = mClients.valueFor(pid);
+ wclient = mClients.valueFor(pid);
- if (wclient != NULL) {
- client = wclient.promote();
- } else {
- client = new Client(this, pid);
- mClients.add(pid, client);
+ if (wclient != NULL) {
+ client = wclient.promote();
+ } else {
+ client = new Client(this, pid);
+ mClients.add(pid, client);
+ }
+
+ track = new Track(this, client, streamType, sampleRate, format,
+ channelCount, frameCount, sharedBuffer);
+ mTracks.add(track);
+ trackHandle = new TrackHandle(track);
+
+ lStatus = NO_ERROR;
}
- // FIXME: Buffer size should be based on sample rate for consistent latency
- track = new Track(this, client, streamType, sampleRate, format,
- channelCount, bufferCount, channelCount == 1 ? mMixBufferSize>>1 : mMixBufferSize);
- mTracks.add(track);
- trackHandle = new TrackHandle(track);
+Exit:
+ if(status) {
+ *status = lStatus;
+ }
return trackHandle;
}
@@ -518,6 +621,16 @@ size_t AudioFlinger::frameCount() const
return mFrameCount;
}
+uint32_t AudioFlinger::latency() const
+{
+ if (mOutput) {
+ return mOutput->latency();
+ }
+ else {
+ return 0;
+ }
+}
+
status_t AudioFlinger::setMasterVolume(float value)
{
// check calling permissions
@@ -549,6 +662,21 @@ status_t AudioFlinger::setRouting(int mode, uint32_t routes, uint32_t mask)
return BAD_VALUE;
}
+#ifdef WITH_A2DP
+ LOGD("setRouting %d %d %d\n", mode, routes, mask);
+ if (mode == AudioSystem::MODE_NORMAL &&
+ (mask & AudioSystem::ROUTE_BLUETOOTH_A2DP)) {
+ if (routes & AudioSystem::ROUTE_BLUETOOTH_A2DP) {
+ LOGD("set output to A2DP\n");
+ setOutput(mA2dpOutput);
+ } else {
+ LOGD("set output to hardware audio\n");
+ setOutput(mHardwareOutput);
+ }
+ LOGD("setOutput done\n");
+ }
+#endif
+
AutoMutex lock(mHardwareLock);
mHardwareStatus = AUDIO_HW_GET_ROUTING;
uint32_t r;
@@ -656,7 +784,7 @@ status_t AudioFlinger::setStreamVolume(int stream, float value)
if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
return BAD_VALUE;
}
-
+
mStreamTypes[stream].volume = value;
status_t ret = NO_ERROR;
if (stream == AudioTrack::VOICE_CALL) {
@@ -750,6 +878,7 @@ status_t AudioFlinger::addTrack(const sp<Track>& track)
// buffers before playing. This is to ensure the client will
// effectively get the latency it requested.
track->mFillingUpStatus = Track::FS_FILLING;
+ track->mResetDone = false;
mActiveTracks.add(track);
return NO_ERROR;
}
@@ -771,7 +900,7 @@ void AudioFlinger::remove_track_l(wp<Track> track, int name)
if (t!=NULL) {
t->reset();
}
- audioMixer().deleteTrackName(name);
+ audioMixer()->deleteTrackName(name);
mActiveTracks.remove(track);
mWaitWorkCV.broadcast();
}
@@ -789,7 +918,7 @@ void AudioFlinger::destroyTrack(const sp<Track>& track)
if (mActiveTracks.indexOf(track) < 0) {
LOGV("remove track (%d) and delete from mixer", track->name());
mTracks.remove(track);
- audioMixer().deleteTrackName(keep->name());
+ audioMixer()->deleteTrackName(keep->name());
}
}
@@ -823,38 +952,53 @@ AudioFlinger::TrackBase::TrackBase(
uint32_t sampleRate,
int format,
int channelCount,
- int bufferCount,
- int bufferSize)
+ int frameCount,
+ const sp<IMemory>& sharedBuffer)
: RefBase(),
mAudioFlinger(audioFlinger),
mClient(client),
mStreamType(streamType),
- mFormat(format),
- mChannelCount(channelCount),
- mBufferCount(bufferCount),
- mFlags(0),
- mBufferSize(bufferSize),
+ mFrameCount(0),
mState(IDLE),
- mClientTid(-1)
+ mClientTid(-1),
+ mFormat(format),
+ mFlags(0)
{
- mName = audioFlinger->audioMixer().getTrackName();
+ mName = audioFlinger->audioMixer()->getTrackName();
if (mName < 0) {
LOGE("no more track names availlable");
return;
}
+ LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
+
+
// LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
- size_t size = sizeof(audio_track_cblk_t) + bufferCount * bufferSize;
+ size_t size = sizeof(audio_track_cblk_t);
+ size_t bufferSize = frameCount*channelCount*sizeof(int16_t);
+ if (sharedBuffer == 0) {
+ size += bufferSize;
+ }
+
mCblkMemory = client->heap()->allocate(size);
if (mCblkMemory != 0) {
mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer());
if (mCblk) { // construct the shared structure in-place.
new(mCblk) audio_track_cblk_t();
// clear all buffers
- mCblk->size = bufferSize;
+ mCblk->frameCount = frameCount;
mCblk->sampleRate = sampleRate;
- mBuffers = (char*)mCblk + sizeof(audio_track_cblk_t);
- memset(mBuffers, 0, bufferCount * bufferSize);
+ mCblk->channels = channelCount;
+ if (sharedBuffer == 0) {
+ mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
+ memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
+ // Force underrun condition to avoid false underrun callback until first data is
+ // written to buffer
+ mCblk->flowControlFlag = 1;
+ } else {
+ mBuffer = sharedBuffer->pointer();
+ }
+ mBufferEnd = (uint8_t *)mBuffer + bufferSize;
}
} else {
LOGE("not enough memory for AudioTrack size=%u", size);
@@ -873,15 +1017,16 @@ AudioFlinger::TrackBase::~TrackBase()
void AudioFlinger::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
{
buffer->raw = 0;
- buffer->frameCount = 0;
+ mFrameCount = buffer->frameCount;
step();
+ buffer->frameCount = 0;
}
bool AudioFlinger::TrackBase::step() {
bool result;
audio_track_cblk_t* cblk = this->cblk();
-
- result = cblk->stepServer(bufferCount());
+
+ result = cblk->stepServer(mFrameCount);
if (!result) {
LOGV("stepServer failed acquiring cblk mutex");
mFlags |= STEPSERVER_FAILED;
@@ -894,7 +1039,10 @@ void AudioFlinger::TrackBase::reset() {
cblk->user = 0;
cblk->server = 0;
- mFlags = 0;
+ cblk->userBase = 0;
+ cblk->serverBase = 0;
+ mFlags = 0;
+ LOGV("TrackBase::reset");
}
sp<IMemory> AudioFlinger::TrackBase::getCblk() const
@@ -906,6 +1054,27 @@ int AudioFlinger::TrackBase::sampleRate() const {
return mCblk->sampleRate;
}
+int AudioFlinger::TrackBase::channelCount() const {
+ return mCblk->channels;
+}
+
+void* AudioFlinger::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
+ audio_track_cblk_t* cblk = this->cblk();
+ int16_t *bufferStart = (int16_t *)mBuffer + (offset-cblk->serverBase)*cblk->channels;
+ int16_t *bufferEnd = bufferStart + frames * cblk->channels;
+
+ // Check validity of returned pointer in case the track control block would have been corrupted.
+ if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd) {
+ LOGW("TrackBase::getBuffer buffer out of range:\n start: %p, end %p , mBuffer %p mBufferEnd %p\n \
+ server %d, serverBase %d, user %d, userBase %d",
+ bufferStart, bufferEnd, mBuffer, mBufferEnd,
+ cblk->server, cblk->serverBase, cblk->user, cblk->userBase);
+ return 0;
+ }
+
+ return bufferStart;
+}
+
// ----------------------------------------------------------------------------
AudioFlinger::Track::Track(
@@ -915,13 +1084,14 @@ AudioFlinger::Track::Track(
uint32_t sampleRate,
int format,
int channelCount,
- int bufferCount,
- int bufferSize)
- : TrackBase(audioFlinger, client, streamType, sampleRate, format, channelCount, bufferCount, bufferSize)
+ int frameCount,
+ const sp<IMemory>& sharedBuffer)
+ : TrackBase(audioFlinger, client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer)
{
mVolume[0] = 1.0f;
mVolume[1] = 1.0f;
mMute = false;
+ mSharedBuffer = sharedBuffer;
}
AudioFlinger::Track::~Track()
@@ -943,8 +1113,8 @@ void AudioFlinger::Track::dump(char* buffer, size_t size)
mClient->pid(),
mStreamType,
mFormat,
- mChannelCount,
- mBufferCount,
+ mCblk->channels,
+ mFrameCount,
mState,
mMute,
mFillingUpStatus,
@@ -958,36 +1128,50 @@ void AudioFlinger::Track::dump(char* buffer, size_t size)
status_t AudioFlinger::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
{
audio_track_cblk_t* cblk = this->cblk();
- uint32_t u = cblk->user;
- uint32_t s = cblk->server;
-
- // Check if last stepServer failed, try to step now
+ uint32_t framesReady;
+ uint32_t framesReq = buffer->frameCount;
+
+ // Check if last stepServer failed, try to step now
if (mFlags & TrackBase::STEPSERVER_FAILED) {
if (!step()) goto getNextBuffer_exit;
LOGV("stepServer recovered");
mFlags &= ~TrackBase::STEPSERVER_FAILED;
}
- if (LIKELY(u > s)) {
- int index = s & audio_track_cblk_t::BUFFER_MASK;
- buffer->raw = getBuffer(index);
- buffer->frameCount = mAudioFlinger->frameCount();
- return NO_ERROR;
+ framesReady = cblk->framesReady();
+
+ if (LIKELY(framesReady)) {
+ uint32_t s = cblk->server;
+ uint32_t bufferEnd = cblk->serverBase + cblk->frameCount;
+
+ bufferEnd = (cblk->loopEnd < bufferEnd) ? cblk->loopEnd : bufferEnd;
+ if (framesReq > framesReady) {
+ framesReq = framesReady;
+ }
+ if (s + framesReq > bufferEnd) {
+ framesReq = bufferEnd - s;
+ }
+
+ buffer->raw = getBuffer(s, framesReq);
+ if (buffer->raw == 0) goto getNextBuffer_exit;
+
+ buffer->frameCount = framesReq;
+ return NO_ERROR;
}
+
getNextBuffer_exit:
buffer->raw = 0;
buffer->frameCount = 0;
return NOT_ENOUGH_DATA;
}
-bool AudioFlinger::Track::isReady(uint32_t u, int32_t s) const {
+bool AudioFlinger::Track::isReady() const {
if (mFillingUpStatus != FS_FILLING) return true;
- const uint32_t u_seq = u & audio_track_cblk_t::SEQUENCE_MASK;
- const uint32_t u_buf = u & audio_track_cblk_t::BUFFER_MASK;
- const uint32_t s_seq = s & audio_track_cblk_t::SEQUENCE_MASK;
- const uint32_t s_buf = s & audio_track_cblk_t::BUFFER_MASK;
- if (u_seq > s_seq && u_buf == s_buf) {
+
+ if (mCblk->framesReady() >= mCblk->frameCount ||
+ mCblk->forceReady) {
mFillingUpStatus = FS_FILLED;
+ mCblk->forceReady = 0;
return true;
}
return false;
@@ -1006,7 +1190,7 @@ void AudioFlinger::Track::stop()
Mutex::Autolock _l(mAudioFlinger->mLock);
if (mState > STOPPED) {
mState = STOPPED;
- // If the track is not active (PAUSED and buffers full), flush buffers
+ // If the track is not active (PAUSED and buffers full), flush buffers
if (mAudioFlinger->mActiveTracks.indexOf(this) < 0) {
reset();
}
@@ -1038,15 +1222,24 @@ void AudioFlinger::Track::flush()
// NOTE: reset() will reset cblk->user and cblk->server with
// the risk that at the same time, the AudioMixer is trying to read
// data. In this case, getNextBuffer() would return a NULL pointer
- // as audio buffer => the AudioMixer code MUST always test that pointer
- // returned by getNextBuffer() is not NULL!
+ // as audio buffer => the AudioMixer code MUST always test that pointer
+ // returned by getNextBuffer() is not NULL!
reset();
}
void AudioFlinger::Track::reset()
{
- TrackBase::reset();
- mFillingUpStatus = FS_FILLING;
+ // Do not reset twice to avoid discarding data written just after a flush and before
+ // the audioflinger thread detects the track is stopped.
+ if (!mResetDone) {
+ TrackBase::reset();
+ // Force underrun condition to avoid false underrun callback until first data is
+ // written to buffer
+ mCblk->flowControlFlag = 1;
+ mCblk->forceReady = 0;
+ mFillingUpStatus = FS_FILLING;
+ mResetDone = true;
+ }
}
void AudioFlinger::Track::mute(bool muted)
@@ -1112,26 +1305,15 @@ status_t AudioFlinger::TrackHandle::onTransact(
// ----------------------------------------------------------------------------
-sp<AudioFlinger::AudioRecordThread> AudioFlinger::audioRecordThread()
-{
- Mutex::Autolock _l(mLock);
- return mAudioRecordThread;
-}
-
-void AudioFlinger::endRecord()
-{
- Mutex::Autolock _l(mLock);
- mAudioRecordThread.clear();
-}
-
sp<IAudioRecord> AudioFlinger::openRecord(
pid_t pid,
int streamType,
uint32_t sampleRate,
int format,
int channelCount,
- int bufferCount,
- uint32_t flags)
+ int frameCount,
+ uint32_t flags,
+ status_t *status)
{
sp<AudioRecordThread> thread;
sp<RecordTrack> recordTrack;
@@ -1139,46 +1321,46 @@ sp<IAudioRecord> AudioFlinger::openRecord(
sp<Client> client;
wp<Client> wclient;
AudioStreamIn* input = 0;
+ int inFrameCount;
+ size_t inputBufferSize;
+ status_t lStatus;
// check calling permissions
if (!recordingAllowed()) {
+ lStatus = PERMISSION_DENIED;
goto Exit;
}
if (uint32_t(streamType) >= AudioRecord::NUM_STREAM_TYPES) {
LOGE("invalid stream type");
+ lStatus = BAD_VALUE;
goto Exit;
}
if (sampleRate > MAX_SAMPLE_RATE) {
LOGE("Sample rate out of range");
+ lStatus = BAD_VALUE;
goto Exit;
}
if (mSampleRate == 0) {
LOGE("Audio driver not initialized");
+ lStatus = NO_INIT;
goto Exit;
}
- // Create audio thread - take mutex to prevent race condition
- {
- Mutex::Autolock _l(mLock);
- if (mAudioRecordThread != 0) {
- LOGE("Record channel already open");
- goto Exit;
- }
- thread = new AudioRecordThread(this);
- mAudioRecordThread = thread;
- }
- // It's safe to release the mutex here since the client doesn't get a
- // handle until we return from this call
-
- // open driver, initialize h/w
- input = mAudioHardware->openInputStream(
- AudioSystem::PCM_16_BIT, channelCount, sampleRate);
- if (!input) {
- LOGE("Error opening input stream");
- mAudioRecordThread.clear();
+ if (mAudioRecordThread == 0) {
+ LOGE("Audio record thread not started");
+ lStatus = NO_INIT;
+ goto Exit;
+ }
+
+
+ // Check that audio input stream accepts requested audio parameters
+ inputBufferSize = mAudioHardware->getInputBufferSize(sampleRate, format, channelCount);
+ if (inputBufferSize == 0) {
+ lStatus = BAD_VALUE;
+ LOGE("Bad audio input parameters: sampling rate %u, format %d, channels %d", sampleRate, format, channelCount);
goto Exit;
}
@@ -1194,37 +1376,38 @@ sp<IAudioRecord> AudioFlinger::openRecord(
}
}
+ // frameCount must be a multiple of input buffer size
+ inFrameCount = inputBufferSize/channelCount/sizeof(short);
+ frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount;
+
// create new record track and pass to record thread
recordTrack = new RecordTrack(this, client, streamType, sampleRate,
- format, channelCount, bufferCount, input->bufferSize());
-
- // spin up record thread
- thread->open(recordTrack, input);
- thread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO);
+ format, channelCount, frameCount);
// return to handle to client
recordHandle = new RecordHandle(recordTrack);
+ lStatus = NO_ERROR;
Exit:
+ if (status) {
+ *status = lStatus;
+ }
return recordHandle;
}
-status_t AudioFlinger::startRecord() {
- sp<AudioRecordThread> t = audioRecordThread();
- if (t == 0) return NO_INIT;
- return t->start();
+status_t AudioFlinger::startRecord(RecordTrack* recordTrack) {
+ if (mAudioRecordThread != 0) {
+ return mAudioRecordThread->start(recordTrack);
+ }
+ return NO_INIT;
}
-void AudioFlinger::stopRecord() {
- sp<AudioRecordThread> t = audioRecordThread();
- if (t != 0) t->stop();
+void AudioFlinger::stopRecord(RecordTrack* recordTrack) {
+ if (mAudioRecordThread != 0) {
+ mAudioRecordThread->stop(recordTrack);
+ }
}
-void AudioFlinger::exitRecord()
-{
- sp<AudioRecordThread> t = audioRecordThread();
- if (t != 0) t->exit();
-}
// ----------------------------------------------------------------------------
@@ -1235,55 +1418,69 @@ AudioFlinger::RecordTrack::RecordTrack(
uint32_t sampleRate,
int format,
int channelCount,
- int bufferCount,
- int bufferSize)
+ int frameCount)
: TrackBase(audioFlinger, client, streamType, sampleRate, format,
- channelCount, bufferCount, bufferSize),
+ channelCount, frameCount, 0),
mOverflow(false)
{
}
AudioFlinger::RecordTrack::~RecordTrack()
{
- mAudioFlinger->audioMixer().deleteTrackName(mName);
- mAudioFlinger->exitRecord();
+ mAudioFlinger->audioMixer()->deleteTrackName(mName);
}
status_t AudioFlinger::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
{
- audio_track_cblk_t* cblk = this->cblk();
- const uint32_t u_seq = cblk->user & audio_track_cblk_t::SEQUENCE_MASK;
- const uint32_t u_buf = cblk->user & audio_track_cblk_t::BUFFER_MASK;
- const uint32_t s_seq = cblk->server & audio_track_cblk_t::SEQUENCE_MASK;
- const uint32_t s_buf = cblk->server & audio_track_cblk_t::BUFFER_MASK;
-
- // Check if last stepServer failed, try to step now
- if (mFlags & TrackBase::STEPSERVER_FAILED) {
- if (!step()) goto getNextBuffer_exit;
- LOGV("stepServer recovered");
- mFlags &= ~TrackBase::STEPSERVER_FAILED;
- }
+ audio_track_cblk_t* cblk = this->cblk();
+ uint32_t framesAvail;
+ uint32_t framesReq = buffer->frameCount;
+
+ // Check if last stepServer failed, try to step now
+ if (mFlags & TrackBase::STEPSERVER_FAILED) {
+ if (!step()) goto getNextBuffer_exit;
+ LOGV("stepServer recovered");
+ mFlags &= ~TrackBase::STEPSERVER_FAILED;
+ }
- if (LIKELY(s_seq == u_seq || s_buf != u_buf)) {
- buffer->raw = getBuffer(s_buf);
- buffer->frameCount = mAudioFlinger->frameCount();
- return NO_ERROR;
- }
+ framesAvail = cblk->framesAvailable_l();
-getNextBuffer_exit:
- buffer->raw = 0;
- buffer->frameCount = 0;
- return NOT_ENOUGH_DATA;
+ if (LIKELY(framesAvail)) {
+ uint32_t s = cblk->server;
+ uint32_t bufferEnd = cblk->serverBase + cblk->frameCount;
+
+ if (framesReq > framesAvail) {
+ framesReq = framesAvail;
+ }
+ if (s + framesReq > bufferEnd) {
+ framesReq = bufferEnd - s;
+ }
+
+ buffer->raw = getBuffer(s, framesReq);
+ if (buffer->raw == 0) goto getNextBuffer_exit;
+
+ buffer->frameCount = framesReq;
+ return NO_ERROR;
+ }
+
+getNextBuffer_exit:
+ buffer->raw = 0;
+ buffer->frameCount = 0;
+ return NOT_ENOUGH_DATA;
}
status_t AudioFlinger::RecordTrack::start()
{
- return mAudioFlinger->startRecord();
+ return mAudioFlinger->startRecord(this);
}
void AudioFlinger::RecordTrack::stop()
{
- mAudioFlinger->stopRecord();
+ mAudioFlinger->stopRecord(this);
+ TrackBase::reset();
+ // Force overerrun condition to avoid false overrun callback until first data is
+ // read from buffer
+ mCblk->flowControlFlag = 1;
}
// ----------------------------------------------------------------------------
@@ -1294,7 +1491,9 @@ AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::RecordTrack>& re
{
}
-AudioFlinger::RecordHandle::~RecordHandle() {}
+AudioFlinger::RecordHandle::~RecordHandle() {
+ stop();
+}
status_t AudioFlinger::RecordHandle::start() {
LOGV("RecordHandle::start()");
@@ -1318,10 +1517,8 @@ status_t AudioFlinger::RecordHandle::onTransact(
// ----------------------------------------------------------------------------
-AudioFlinger::AudioRecordThread::AudioRecordThread(const sp<AudioFlinger>& audioFlinger) :
- mAudioFlinger(audioFlinger),
- mRecordTrack(0),
- mInput(0),
+AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware) :
+ mAudioHardware(audioHardware),
mActive(false)
{
}
@@ -1333,108 +1530,123 @@ AudioFlinger::AudioRecordThread::~AudioRecordThread()
bool AudioFlinger::AudioRecordThread::threadLoop()
{
LOGV("AudioRecordThread: start record loop");
+ AudioBufferProvider::Buffer buffer;
+ int inBufferSize = 0;
+ int inFrameCount = 0;
+ AudioStreamIn* input = 0;
+ mActive = 0;
+
// start recording
while (!exitPending()) {
if (!mActive) {
mLock.lock();
if (!mActive && !exitPending()) {
LOGV("AudioRecordThread: loop stopping");
+ if (input) {
+ delete input;
+ input = 0;
+ }
+ mRecordTrack.clear();
+
mWaitWorkCV.wait(mLock);
+
LOGV("AudioRecordThread: loop starting");
+ if (mRecordTrack != 0) {
+ input = mAudioHardware->openInputStream(mRecordTrack->format(),
+ mRecordTrack->channelCount(),
+ mRecordTrack->sampleRate(),
+ &mStartStatus);
+ if (input != 0) {
+ inBufferSize = input->bufferSize();
+ inFrameCount = inBufferSize/input->frameSize();
+ }
+ } else {
+ mStartStatus = NO_INIT;
+ }
+ if (mStartStatus !=NO_ERROR) {
+ LOGW("record start failed, status %d", mStartStatus);
+ mActive = false;
+ mRecordTrack.clear();
+ }
+ mWaitWorkCV.signal();
}
mLock.unlock();
- } else {
- // promote strong ref so track isn't deleted while we access it
- sp<RecordTrack> t = mRecordTrack.promote();
+ } else if (mRecordTrack != 0){
- // if we lose the weak reference, client is gone.
- if (t == 0) {
- LOGV("AudioRecordThread: client deleted track");
- break;
- }
-
- if (LIKELY(t->getNextBuffer(&mBuffer) == NO_ERROR)) {
- if (mInput->read(mBuffer.raw, t->mBufferSize) < 0) {
+ buffer.frameCount = inFrameCount;
+ if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR)) {
+ LOGV("AudioRecordThread read: %d frames", buffer.frameCount);
+ if (input->read(buffer.raw, inBufferSize) < 0) {
LOGE("Error reading audio input");
sleep(1);
}
- t->releaseBuffer(&mBuffer);
+ mRecordTrack->releaseBuffer(&buffer);
+ mRecordTrack->overflow();
}
// client isn't retrieving buffers fast enough
else {
- if (!t->setOverflow())
+ if (!mRecordTrack->setOverflow())
LOGW("AudioRecordThread: buffer overflow");
+ // Release the processor for a while before asking for a new buffer.
+ // This will give the application more chance to read from the buffer and
+ // clear the overflow.
+ usleep(5000);
}
}
- };
-
- // close hardware
- close();
+ }
- // delete this object - no more data references after this call
- mAudioFlinger->endRecord();
- return false;
-}
-status_t AudioFlinger::AudioRecordThread::open(const sp<RecordTrack>& recordTrack, AudioStreamIn *input) {
- LOGV("AudioRecordThread::open");
- // check for record channel already open
- AutoMutex lock(&mLock);
- if (mRecordTrack != NULL) {
- LOGE("Record channel already open");
- return ALREADY_EXISTS;
+ if (input) {
+ delete input;
}
- mRecordTrack = recordTrack;
- mInput = input;
- return NO_ERROR;
+ mRecordTrack.clear();
+
+ return false;
}
-status_t AudioFlinger::AudioRecordThread::start()
+status_t AudioFlinger::AudioRecordThread::start(RecordTrack* recordTrack)
{
LOGV("AudioRecordThread::start");
AutoMutex lock(&mLock);
- if (mActive) return -EBUSY;
+ mActive = true;
+ // If starting the active track, just reset mActive in case a stop
+ // was pending and exit
+ if (recordTrack == mRecordTrack.get()) return NO_ERROR;
+
+ if (mRecordTrack != 0) return -EBUSY;
- sp<RecordTrack> t = mRecordTrack.promote();
- if (t == 0) return UNKNOWN_ERROR;
+ mRecordTrack = recordTrack;
// signal thread to start
LOGV("Signal record thread");
- mActive = true;
mWaitWorkCV.signal();
- return NO_ERROR;
+ mWaitWorkCV.wait(mLock);
+ LOGV("Record started, status %d", mStartStatus);
+ return mStartStatus;
}
-void AudioFlinger::AudioRecordThread::stop() {
+void AudioFlinger::AudioRecordThread::stop(RecordTrack* recordTrack) {
LOGV("AudioRecordThread::stop");
AutoMutex lock(&mLock);
- if (mActive) {
+ if (mActive && (recordTrack == mRecordTrack.get())) {
mActive = false;
- mWaitWorkCV.signal();
}
}
void AudioFlinger::AudioRecordThread::exit()
{
LOGV("AudioRecordThread::exit");
- AutoMutex lock(&mLock);
- requestExit();
- mWaitWorkCV.signal();
+ {
+ AutoMutex lock(&mLock);
+ requestExit();
+ mWaitWorkCV.signal();
+ }
+ requestExitAndWait();
}
-status_t AudioFlinger::AudioRecordThread::close()
-{
- LOGV("AudioRecordThread::close");
- AutoMutex lock(&mLock);
- if (!mInput) return NO_INIT;
- delete mInput;
- mInput = 0;
- return NO_ERROR;
-}
-
status_t AudioFlinger::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 8c02617..d9f7b49 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -43,13 +43,17 @@ class audio_track_cblk_t;
class AudioMixer;
class AudioBuffer;
+
// ----------------------------------------------------------------------------
#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
// ----------------------------------------------------------------------------
+static const nsecs_t kStandbyTimeInNsecs = seconds(3);
+
class AudioFlinger : public BnAudioFlinger, protected Thread
{
public:
@@ -69,13 +73,16 @@ public:
uint32_t sampleRate,
int format,
int channelCount,
- int bufferCount,
- uint32_t flags);
+ int frameCount,
+ uint32_t flags,
+ const sp<IMemory>& sharedBuffer,
+ status_t *status);
virtual uint32_t sampleRate() const;
virtual int channelCount() const;
virtual int format() const;
virtual size_t frameCount() const;
+ virtual size_t latency() const;
virtual status_t setMasterVolume(float value);
virtual status_t setMasterMute(bool muted);
@@ -128,8 +135,9 @@ public:
uint32_t sampleRate,
int format,
int channelCount,
- int bufferCount,
- uint32_t flags);
+ int frameCount,
+ uint32_t flags,
+ status_t *status);
virtual status_t onTransact(
uint32_t code,
@@ -141,12 +149,15 @@ private:
AudioFlinger();
virtual ~AudioFlinger();
+ void setOutput(AudioStreamOut* output);
+ size_t getOutputFrameCount(AudioStreamOut* output);
+
// Internal dump utilites.
status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
status_t dumpClients(int fd, const Vector<String16>& args);
status_t dumpTracks(int fd, const Vector<String16>& args);
status_t dumpInternals(int fd, const Vector<String16>& args);
-
+
// --- Client ---
class Client : public RefBase {
public:
@@ -183,17 +194,17 @@ private:
};
enum track_flags {
- STEPSERVER_FAILED = 0x01 // StepServer could not acquire cblk->lock mutex
+ STEPSERVER_FAILED = 0x01 // StepServer could not acquire cblk->lock mutex
};
-
+
TrackBase( const sp<AudioFlinger>& audioFlinger,
const sp<Client>& client,
int streamType,
uint32_t sampleRate,
int format,
int channelCount,
- int bufferCount,
- int bufferSize);
+ int frameCount,
+ const sp<IMemory>& sharedBuffer);
~TrackBase();
virtual status_t start() = 0;
@@ -203,6 +214,7 @@ private:
protected:
friend class AudioFlinger;
friend class RecordHandle;
+ friend class AudioRecordThread;
TrackBase(const TrackBase&);
TrackBase& operator = (const TrackBase&);
@@ -222,19 +234,11 @@ private:
return mFormat;
}
- int channelCount() const {
- return mChannelCount;
- }
-
- int bufferCount() const {
- return mBufferCount;
- }
+ int channelCount() const ;
int sampleRate() const;
- void* getBuffer(int n) const {
- return (char*)mBuffers + n * mBufferSize;
- }
+ void* getBuffer(uint32_t offset, uint32_t frames) const;
int name() const {
return mName;
@@ -256,16 +260,15 @@ private:
sp<IMemory> mCblkMemory;
audio_track_cblk_t* mCblk;
int mStreamType;
- uint8_t mFormat;
- uint8_t mChannelCount;
- uint8_t mBufferCount;
- uint8_t mFlags;
- void* mBuffers;
- size_t mBufferSize;
+ void* mBuffer;
+ void* mBufferEnd;
+ uint32_t mFrameCount;
int mName;
// we don't really need a lock for these
int mState;
int mClientTid;
+ uint8_t mFormat;
+ uint8_t mFlags;
};
// playback track
@@ -277,8 +280,8 @@ private:
uint32_t sampleRate,
int format,
int channelCount,
- int bufferCount,
- int bufferSize);
+ int frameCount,
+ const sp<IMemory>& sharedBuffer);
~Track();
void dump(char* buffer, size_t size);
@@ -312,7 +315,7 @@ private:
return mState == PAUSED;
}
- bool isReady(uint32_t u, int32_t s) const;
+ bool isReady() const;
void setPaused() { mState = PAUSED; }
void reset();
@@ -324,6 +327,8 @@ private:
enum {FS_FILLING, FS_FILLED, FS_ACTIVE};
mutable uint8_t mFillingUpStatus;
int8_t mRetryCount;
+ sp<IMemory> mSharedBuffer;
+ bool mResetDone;
}; // end of Track
friend class AudioBuffer;
@@ -366,8 +371,8 @@ private:
void remove_track_l(wp<Track> track, int name);
void destroyTrack(const sp<Track>& track);
- AudioMixer& audioMixer() {
- return *mAudioMixer;
+ AudioMixer* audioMixer() {
+ return mAudioMixer;
}
// record track
@@ -379,8 +384,7 @@ private:
uint32_t sampleRate,
int format,
int channelCount,
- int bufferCount,
- int bufferSize);
+ int frameCount);
~RecordTrack();
virtual status_t start();
@@ -419,43 +423,34 @@ private:
class AudioRecordThread : public Thread
{
public:
- AudioRecordThread(const sp<AudioFlinger>& audioFlinger);
+ AudioRecordThread(AudioHardwareInterface* audioHardware);
virtual ~AudioRecordThread();
virtual bool threadLoop();
virtual status_t readyToRun() { return NO_ERROR; }
virtual void onFirstRef() {}
- status_t open(const sp<RecordTrack>& recordTrack, AudioStreamIn *input);
- status_t start();
- void stop();
- status_t close();
+ status_t start(RecordTrack* recordTrack);
+ void stop(RecordTrack* recordTrack);
void exit();
-
- bool isOpen() { return bool(mRecordTrack != NULL); }
private:
AudioRecordThread();
- sp<AudioFlinger> mAudioFlinger;
- wp<RecordTrack> mRecordTrack;
- AudioStreamIn* mInput;
+ AudioHardwareInterface *mAudioHardware;
+ sp<RecordTrack> mRecordTrack;
Mutex mLock;
Condition mWaitWorkCV;
- AudioBufferProvider::Buffer mBuffer;
volatile bool mActive;
+ status_t mStartStatus;
};
friend class AudioRecordThread;
- sp<AudioRecordThread> audioRecordThread();
- void endRecord();
- status_t startRecord();
- void stopRecord();
- void exitRecord();
-
- AudioHardwareInterface* audioHardware() { return mAudioHardware; }
+ status_t startRecord(RecordTrack* recordTrack);
+ void stopRecord(RecordTrack* recordTrack);
mutable Mutex mHardwareLock;
mutable Mutex mLock;
+ mutable Mutex mOutputLock;
mutable Condition mWaitWorkCV;
DefaultKeyedVector< pid_t, wp<Client> > mClients;
SortedVector< wp<Track> > mActiveTracks;
@@ -465,15 +460,19 @@ private:
bool mMasterMute;
stream_type_t mStreamTypes[AudioTrack::NUM_STREAM_TYPES];
+ AudioMixer* mHardwareAudioMixer;
+ AudioMixer* mA2dpAudioMixer;
AudioMixer* mAudioMixer;
AudioHardwareInterface* mAudioHardware;
+ AudioHardwareInterface* mA2dpAudioInterface;
+ AudioStreamOut* mHardwareOutput;
+ AudioStreamOut* mA2dpOutput;
AudioStreamOut* mOutput;
sp<AudioRecordThread> mAudioRecordThread;
uint32_t mSampleRate;
size_t mFrameCount;
int mChannelCount;
int mFormat;
- int mMixBufferSize;
int16_t* mMixBuffer;
mutable int mHardwareStatus;
nsecs_t mLastWriteTime;
diff --git a/libs/audioflinger/AudioHardwareGeneric.cpp b/libs/audioflinger/AudioHardwareGeneric.cpp
index b1e5b7f..e6a163b 100644
--- a/libs/audioflinger/AudioHardwareGeneric.cpp
+++ b/libs/audioflinger/AudioHardwareGeneric.cpp
@@ -2,16 +2,16 @@
**
** Copyright 2007, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
@@ -68,16 +68,25 @@ status_t AudioHardwareGeneric::standby()
}
AudioStreamOut* AudioHardwareGeneric::openOutputStream(
- int format, int channelCount, uint32_t sampleRate)
+ int format, int channelCount, uint32_t sampleRate, status_t *status)
{
AutoMutex lock(mLock);
// only one output stream allowed
- if (mOutput) return 0;
+ if (mOutput) {
+ if (status) {
+ *status = INVALID_OPERATION;
+ }
+ return 0;
+ }
// create new output stream
AudioStreamOutGeneric* out = new AudioStreamOutGeneric();
- if (out->set(this, mFd, format, channelCount, sampleRate) == NO_ERROR) {
+ status_t lStatus = out->set(this, mFd, format, channelCount, sampleRate);
+ if (status) {
+ *status = lStatus;
+ }
+ if (lStatus == NO_ERROR) {
mOutput = out;
} else {
delete out;
@@ -90,16 +99,25 @@ void AudioHardwareGeneric::closeOutputStream(AudioStreamOutGeneric* out) {
}
AudioStreamIn* AudioHardwareGeneric::openInputStream(
- int format, int channelCount, uint32_t sampleRate)
+ int format, int channelCount, uint32_t sampleRate, status_t *status)
{
AutoMutex lock(mLock);
// only one input stream allowed
- if (mInput) return 0;
+ if (mInput) {
+ if (status) {
+ *status = INVALID_OPERATION;
+ }
+ return 0;
+ }
// create new output stream
AudioStreamInGeneric* in = new AudioStreamInGeneric();
- if (in->set(this, mFd, format, channelCount, sampleRate) == NO_ERROR) {
+ status_t lStatus = in->set(this, mFd, format, channelCount, sampleRate);
+ if (status) {
+ *status = lStatus;
+ }
+ if (lStatus == NO_ERROR) {
mInput = in;
} else {
delete in;
diff --git a/libs/audioflinger/AudioHardwareGeneric.h b/libs/audioflinger/AudioHardwareGeneric.h
index 10cc45d..a2342cd 100644
--- a/libs/audioflinger/AudioHardwareGeneric.h
+++ b/libs/audioflinger/AudioHardwareGeneric.h
@@ -2,16 +2,16 @@
**
** Copyright 2007, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
@@ -23,7 +23,7 @@
#include <utils/threads.h>
-#include <hardware/AudioHardwareInterface.h>
+#include <hardware/AudioHardwareBase.h>
namespace android {
@@ -47,6 +47,7 @@ public:
virtual size_t bufferSize() const { return 4096; }
virtual int channelCount() const { return 2; }
virtual int format() const { return AudioSystem::PCM_16_BIT; }
+ virtual uint32_t latency() const { return 0; }
virtual status_t setVolume(float volume) { return INVALID_OPERATION; }
virtual ssize_t write(const void* buffer, size_t bytes);
virtual status_t dump(int fd, const Vector<String16>& args);
@@ -76,6 +77,7 @@ public:
virtual status_t setGain(float gain) { return INVALID_OPERATION; }
virtual ssize_t read(void* buffer, ssize_t bytes);
virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t standby() { return NO_ERROR; }
private:
AudioHardwareGeneric *mAudioHardware;
@@ -84,7 +86,7 @@ private:
};
-class AudioHardwareGeneric : public AudioHardwareInterface
+class AudioHardwareGeneric : public AudioHardwareBase
{
public:
AudioHardwareGeneric();
@@ -105,12 +107,14 @@ public:
virtual AudioStreamOut* openOutputStream(
int format=0,
int channelCount=0,
- uint32_t sampleRate=0);
+ uint32_t sampleRate=0,
+ status_t *status=0);
virtual AudioStreamIn* openInputStream(
int format,
int channelCount,
- uint32_t sampleRate);
+ uint32_t sampleRate,
+ status_t *status);
void closeOutputStream(AudioStreamOutGeneric* out);
void closeInputStream(AudioStreamInGeneric* in);
@@ -120,7 +124,7 @@ protected:
private:
status_t dumpInternals(int fd, const Vector<String16>& args);
-
+
Mutex mLock;
AudioStreamOutGeneric *mOutput;
AudioStreamInGeneric *mInput;
diff --git a/libs/audioflinger/AudioHardwareInterface.cpp b/libs/audioflinger/AudioHardwareInterface.cpp
index 7387b3d..ac76a19 100644
--- a/libs/audioflinger/AudioHardwareInterface.cpp
+++ b/libs/audioflinger/AudioHardwareInterface.cpp
@@ -26,7 +26,7 @@
#include "AudioHardwareStub.h"
#include "AudioHardwareGeneric.h"
-// #define DUMP_FLINGER_OUT // if defined allows recording samples in a file
+//#define DUMP_FLINGER_OUT // if defined allows recording samples in a file
#ifdef DUMP_FLINGER_OUT
#include "AudioDumpInterface.h"
#endif
@@ -54,6 +54,7 @@ static const char* routeStrings[] =
"SPEAKER ",
"BLUETOOTH ",
"HEADSET "
+ "BLUETOOTH_A2DP "
};
static const char* routeNone = "NONE";
@@ -115,24 +116,10 @@ AudioHardwareInterface* AudioHardwareInterface::create()
// This code adds a record of buffers in a file to write calls made by AudioFlinger.
// It replaces the current AudioHardwareInterface object by an intermediate one which
// will record buffers in a file (after sending them to hardware) for testing purpose.
- // This feature is enabled by defining symbol DUMP_FLINGER_OUT and setting environement
- // "audioflinger.dump = 1". The output file is "tmp/FlingerOut.pcm". Pause are not recorded
- // in the file.
+ // This feature is enabled by defining symbol DUMP_FLINGER_OUT.
+ // The output file is FLINGER_DUMP_NAME. Pause are not recorded in the file.
- // read dump mode
- property_get("audioflinger.dump", value, "0");
- switch(value[0]) {
- case '1':
- LOGV("Dump mode");
- hw = new AudioDumpInterface(hw); // replace interface
- return hw;
- break;
- case '0':
- default:
- LOGV("No Dump mode");
- return hw;
- break;
- }
+ hw = new AudioDumpInterface(hw); // replace interface
#endif
return hw;
}
@@ -143,7 +130,7 @@ AudioStreamOut::~AudioStreamOut()
AudioStreamIn::~AudioStreamIn() {}
-AudioHardwareInterface::AudioHardwareInterface()
+AudioHardwareBase::AudioHardwareBase()
{
// force a routing update on initialization
memset(&mRoutes, 0, sizeof(mRoutes));
@@ -151,7 +138,7 @@ AudioHardwareInterface::AudioHardwareInterface()
}
// generics for audio routing - the real work is done in doRouting
-status_t AudioHardwareInterface::setRouting(int mode, uint32_t routes)
+status_t AudioHardwareBase::setRouting(int mode, uint32_t routes)
{
#if LOG_ROUTING_CALLS
LOGD("setRouting: mode=%s, routes=[%s]", displayMode(mode), displayRoutes(routes));
@@ -173,7 +160,7 @@ status_t AudioHardwareInterface::setRouting(int mode, uint32_t routes)
return doRouting();
}
-status_t AudioHardwareInterface::getRouting(int mode, uint32_t* routes)
+status_t AudioHardwareBase::getRouting(int mode, uint32_t* routes)
{
if (mode == AudioSystem::MODE_CURRENT)
mode = mMode;
@@ -187,7 +174,7 @@ status_t AudioHardwareInterface::getRouting(int mode, uint32_t* routes)
return NO_ERROR;
}
-status_t AudioHardwareInterface::setMode(int mode)
+status_t AudioHardwareBase::setMode(int mode)
{
#if LOG_ROUTING_CALLS
LOGD("setMode(%s)", displayMode(mode));
@@ -204,25 +191,45 @@ status_t AudioHardwareInterface::setMode(int mode)
return doRouting();
}
-status_t AudioHardwareInterface::getMode(int* mode)
+status_t AudioHardwareBase::getMode(int* mode)
{
// Implement: set audio routing
*mode = mMode;
return NO_ERROR;
}
-status_t AudioHardwareInterface::setParameter(const char* key, const char* value)
+status_t AudioHardwareBase::setParameter(const char* key, const char* value)
{
// default implementation is to ignore
return NO_ERROR;
}
-status_t AudioHardwareInterface::dumpState(int fd, const Vector<String16>& args)
+
+// default implementation
+size_t AudioHardwareBase::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+ if (sampleRate != 8000) {
+ LOGW("getInputBufferSize bad sampling rate: %d", sampleRate);
+ return 0;
+ }
+ if (format != AudioSystem::PCM_16_BIT) {
+ LOGW("getInputBufferSize bad format: %d", format);
+ return 0;
+ }
+ if (channelCount != 1) {
+ LOGW("getInputBufferSize bad channel count: %d", channelCount);
+ return 0;
+ }
+
+ return 320;
+}
+
+status_t AudioHardwareBase::dumpState(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
- snprintf(buffer, SIZE, "AudioHardwareInterface::dumpState\n");
+ snprintf(buffer, SIZE, "AudioHardwareBase::dumpState\n");
result.append(buffer);
snprintf(buffer, SIZE, "\tmMode: %d\n", mMode);
result.append(buffer);
diff --git a/libs/audioflinger/AudioHardwareStub.cpp b/libs/audioflinger/AudioHardwareStub.cpp
index 0046db8..d309902 100644
--- a/libs/audioflinger/AudioHardwareStub.cpp
+++ b/libs/audioflinger/AudioHardwareStub.cpp
@@ -2,16 +2,16 @@
**
** Copyright 2007, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
@@ -47,20 +47,28 @@ status_t AudioHardwareStub::standby()
}
AudioStreamOut* AudioHardwareStub::openOutputStream(
- int format, int channelCount, uint32_t sampleRate)
+ int format, int channelCount, uint32_t sampleRate, status_t *status)
{
AudioStreamOutStub* out = new AudioStreamOutStub();
- if (out->set(format, channelCount, sampleRate) == NO_ERROR)
+ status_t lStatus = out->set(format, channelCount, sampleRate);
+ if (status) {
+ *status = lStatus;
+ }
+ if (lStatus == NO_ERROR)
return out;
delete out;
return 0;
}
AudioStreamIn* AudioHardwareStub::openInputStream(
- int format, int channelCount, uint32_t sampleRate)
+ int format, int channelCount, uint32_t sampleRate, status_t *status)
{
AudioStreamInStub* in = new AudioStreamInStub();
- if (in->set(format, channelCount, sampleRate) == NO_ERROR)
+ status_t lStatus = in->set(format, channelCount, sampleRate);
+ if (status) {
+ *status = lStatus;
+ }
+ if (lStatus == NO_ERROR)
return in;
delete in;
return 0;
@@ -102,7 +110,7 @@ status_t AudioStreamOutStub::set(int format, int channels, uint32_t rate)
if (format == 0) format = AudioSystem::PCM_16_BIT;
if (channels == 0) channels = channelCount();
if (rate == 0) rate = sampleRate();
-
+
if ((format == AudioSystem::PCM_16_BIT) &&
(channels == channelCount()) &&
(rate == sampleRate()))
@@ -129,7 +137,7 @@ status_t AudioStreamOutStub::dump(int fd, const Vector<String16>& args)
snprintf(buffer, SIZE, "\tformat: %d\n", format());
result.append(buffer);
::write(fd, result.string(), result.size());
- return NO_ERROR;
+ return NO_ERROR;
}
// ----------------------------------------------------------------------------
diff --git a/libs/audioflinger/AudioHardwareStub.h b/libs/audioflinger/AudioHardwareStub.h
index 1a61552..5316d60 100644
--- a/libs/audioflinger/AudioHardwareStub.h
+++ b/libs/audioflinger/AudioHardwareStub.h
@@ -2,16 +2,16 @@
**
** Copyright 2007, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
@@ -21,7 +21,7 @@
#include <stdint.h>
#include <sys/types.h>
-#include <hardware/AudioHardwareInterface.h>
+#include <hardware/AudioHardwareBase.h>
namespace android {
@@ -34,6 +34,7 @@ public:
virtual size_t bufferSize() const { return 4096; }
virtual int channelCount() const { return 2; }
virtual int format() const { return AudioSystem::PCM_16_BIT; }
+ virtual uint32_t latency() const { return 0; }
virtual status_t setVolume(float volume) { return NO_ERROR; }
virtual ssize_t write(const void* buffer, size_t bytes);
virtual status_t dump(int fd, const Vector<String16>& args);
@@ -49,9 +50,10 @@ public:
virtual status_t setGain(float gain) { return NO_ERROR; }
virtual ssize_t read(void* buffer, ssize_t bytes);
virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t standby() { return NO_ERROR; }
};
-class AudioHardwareStub : public AudioHardwareInterface
+class AudioHardwareStub : public AudioHardwareBase
{
public:
AudioHardwareStub();
@@ -72,12 +74,14 @@ public:
virtual AudioStreamOut* openOutputStream(
int format=0,
int channelCount=0,
- uint32_t sampleRate=0);
+ uint32_t sampleRate=0,
+ status_t *status=0);
virtual AudioStreamIn* openInputStream(
int format,
int channelCount,
- uint32_t sampleRate);
+ uint32_t sampleRate,
+ status_t *status);
protected:
virtual status_t doRouting() { return NO_ERROR; }
diff --git a/libs/audioflinger/AudioMixer.cpp b/libs/audioflinger/AudioMixer.cpp
index 9f1b17f..b03467f 100644
--- a/libs/audioflinger/AudioMixer.cpp
+++ b/libs/audioflinger/AudioMixer.cpp
@@ -2,16 +2,16 @@
**
** Copyright 2007, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
@@ -247,8 +247,8 @@ inline
void AudioMixer::track_t::adjustVolumeRamp()
{
for (int i=0 ; i<2 ; i++) {
- if (((volumeInc[i]>0) && ((prevVolume[i]>>16) >= volume[i])) ||
- ((volumeInc[i]<0) && ((prevVolume[i]>>16) <= volume[i]))) {
+ if (((volumeInc[i]>0) && (((prevVolume[i]+volumeInc[i])>>16) >= volume[i])) ||
+ ((volumeInc[i]<0) && (((prevVolume[i]+volumeInc[i])>>16) <= volume[i]))) {
volumeInc[i] = 0;
prevVolume[i] = volume[i]<<16;
}
@@ -307,7 +307,7 @@ void AudioMixer::process__validate(state_t* state, void* output)
n |= NEEDS_CHANNEL_1 + t.channelCount - 1;
n |= NEEDS_FORMAT_16;
n |= t.doesResample() ? NEEDS_RESAMPLE_ENABLED : NEEDS_RESAMPLE_DISABLED;
-
+
if (t.volumeInc[0]|t.volumeInc[1]) {
volumeRamp = 1;
} else if (!t.doesResample() && t.volumeRL == 0) {
@@ -370,7 +370,7 @@ void AudioMixer::process__validate(state_t* state, void* output)
state->hook(state, output);
- // Now that the volume ramp has been done, set optimal state and
+ // Now that the volume ramp has been done, set optimal state and
// track hooks for subsequent mixer process
if (countActiveTracks) {
int allMuted = 1;
@@ -397,7 +397,7 @@ void AudioMixer::process__validate(state_t* state, void* output)
}
}
-static inline
+static inline
int32_t mulAdd(int16_t in, int16_t v, int32_t a)
{
#if defined(__arm__) && !defined(__thumb__)
@@ -412,7 +412,7 @@ int32_t mulAdd(int16_t in, int16_t v, int32_t a)
#endif
}
-static inline
+static inline
int32_t mul(int16_t in, int16_t v)
{
#if defined(__arm__) && !defined(__thumb__)
@@ -427,7 +427,7 @@ int32_t mul(int16_t in, int16_t v)
#endif
}
-static inline
+static inline
int32_t mulAddRL(int left, uint32_t inRL, uint32_t vRL, int32_t a)
{
#if defined(__arm__) && !defined(__thumb__)
@@ -453,7 +453,7 @@ int32_t mulAddRL(int left, uint32_t inRL, uint32_t vRL, int32_t a)
#endif
}
-static inline
+static inline
int32_t mulRL(int left, uint32_t inRL, uint32_t vRL)
{
#if defined(__arm__) && !defined(__thumb__)
@@ -513,7 +513,7 @@ void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, i
//LOGD("[0] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
// t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
// (vl + vlInc*frameCount)/65536.0f, frameCount);
-
+
// ramp volume
do {
*out++ += (vl >> 16) * (*temp++ >> 12);
@@ -548,7 +548,7 @@ void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount
vl += vlInc;
vr += vrInc;
} while (--frameCount);
-
+
t->prevVolume[0] = vl;
t->prevVolume[1] = vr;
t->adjustVolumeRamp();
@@ -590,7 +590,7 @@ void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount,
vl += vlInc;
vr += vrInc;
} while (--frameCount);
-
+
t->prevVolume[0] = vl;
t->prevVolume[1] = vr;
t->adjustVolumeRamp();
@@ -609,7 +609,7 @@ void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount,
t->in = in;
}
-inline
+inline
void AudioMixer::ditherAndClamp(int32_t* out, int32_t const *sums, size_t c)
{
for (size_t i=0 ; i<c ; i++) {
@@ -633,8 +633,12 @@ void AudioMixer::process__nop(state_t* state, void* output)
const int i = 31 - __builtin_clz(en);
en &= ~(1<<i);
track_t& t = state->tracks[i];
- t.bufferProvider->getNextBuffer(&t.buffer);
- if (t.buffer.raw) {
+ size_t outFrames = state->frameCount;
+ while (outFrames) {
+ t.buffer.frameCount = outFrames;
+ t.bufferProvider->getNextBuffer(&t.buffer);
+ if (!t.buffer.raw) break;
+ outFrames -= t.buffer.frameCount;
t.bufferProvider->releaseBuffer(&t.buffer);
}
}
@@ -652,12 +656,14 @@ void AudioMixer::process__genericNoResampling(state_t* state, void* output)
const int i = 31 - __builtin_clz(en);
en &= ~(1<<i);
track_t& t = state->tracks[i];
+ t.buffer.frameCount = state->frameCount;
t.bufferProvider->getNextBuffer(&t.buffer);
+ t.frameCount = t.buffer.frameCount;
t.in = t.buffer.raw;
// t.in == NULL can happen if the track was flushed just after having
// been enabled for mixing.
if (t.in == NULL)
- enabledTracks &= ~(1<<i);
+ enabledTracks &= ~(1<<i);
}
// this assumes output 16 bits stereo, no resampling
@@ -671,12 +677,31 @@ void AudioMixer::process__genericNoResampling(state_t* state, void* output)
const int i = 31 - __builtin_clz(en);
en &= ~(1<<i);
track_t& t = state->tracks[i];
- (t.hook)(&t, outTemp, BLOCKSIZE, state->resampleTemp);
+ size_t outFrames = BLOCKSIZE;
+
+ while (outFrames) {
+ size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount;
+ if (inFrames) {
+ (t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp);
+ t.frameCount -= inFrames;
+ outFrames -= inFrames;
+ }
+ if (t.frameCount == 0 && outFrames) {
+ t.bufferProvider->releaseBuffer(&t.buffer);
+ t.buffer.frameCount = numFrames - (BLOCKSIZE - outFrames);
+ t.bufferProvider->getNextBuffer(&t.buffer);
+ t.in = t.buffer.raw;
+ if (t.in == NULL) {
+ enabledTracks &= ~(1<<i);
+ break;
+ }
+ t.frameCount = t.buffer.frameCount;
+ }
+ }
}
ditherAndClamp(out, outTemp, BLOCKSIZE);
out += BLOCKSIZE;
-
numFrames -= BLOCKSIZE;
} while (numFrames);
@@ -713,12 +738,19 @@ void AudioMixer::process__genericResampling(state_t* state, void* output)
if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
(t.hook)(&t, outTemp, numFrames, state->resampleTemp);
} else {
- t.bufferProvider->getNextBuffer(&t.buffer);
- t.in = t.buffer.raw;
- // t.in == NULL can happen if the track was flushed just after having
- // been enabled for mixing.
- if (t.in) {
- (t.hook)(&t, outTemp, numFrames, state->resampleTemp);
+
+ size_t outFrames = numFrames;
+
+ while (outFrames) {
+ t.buffer.frameCount = outFrames;
+ t.bufferProvider->getNextBuffer(&t.buffer);
+ t.in = t.buffer.raw;
+ // t.in == NULL can happen if the track was flushed just after having
+ // been enabled for mixing.
+ if (t.in == NULL) break;
+
+ (t.hook)(&t, outTemp + (numFrames-outFrames)*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp);
+ outFrames -= t.buffer.frameCount;
t.bufferProvider->releaseBuffer(&t.buffer);
}
}
@@ -734,45 +766,51 @@ void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, void*
const track_t& t = state->tracks[i];
AudioBufferProvider::Buffer& b(t.buffer);
- t.bufferProvider->getNextBuffer(&b);
- int16_t const *in = t.buffer.i16;
-
- // in == NULL can happen if the track was flushed just after having
- // been enabled for mixing.
- if (in == NULL) {
- memset(output, 0, state->frameCount*MAX_NUM_CHANNELS*sizeof(int16_t));
- return;
- }
-
+
int32_t* out = static_cast<int32_t*>(output);
size_t numFrames = state->frameCount;
+
const int16_t vl = t.volume[0];
const int16_t vr = t.volume[1];
const uint32_t vrl = t.volumeRL;
- if (UNLIKELY(uint32_t(vl) > UNITY_GAIN || uint32_t(vr) > UNITY_GAIN)) {
- // volume is boosted, so we might need to clamp even though
- // we process only one track.
- do {
- uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
- in += 2;
- int32_t l = mulRL(1, rl, vrl) >> 12;
- int32_t r = mulRL(0, rl, vrl) >> 12;
- // clamping...
- l = clamp16(l);
- r = clamp16(r);
- *out++ = (r<<16) | (l & 0xFFFF);
- } while (--numFrames);
- } else {
- do {
- uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
- in += 2;
- int32_t l = mulRL(1, rl, vrl) >> 12;
- int32_t r = mulRL(0, rl, vrl) >> 12;
- *out++ = (r<<16) | (l & 0xFFFF);
- } while (--numFrames);
- }
+ while (numFrames) {
+ b.frameCount = numFrames;
+ t.bufferProvider->getNextBuffer(&b);
+ int16_t const *in = b.i16;
- t.bufferProvider->releaseBuffer(&b);
+ // in == NULL can happen if the track was flushed just after having
+ // been enabled for mixing.
+ if (in == NULL) {
+ memset(out, 0, numFrames*MAX_NUM_CHANNELS*sizeof(int16_t));
+ return;
+ }
+ size_t outFrames = b.frameCount;
+
+ if (UNLIKELY(uint32_t(vl) > UNITY_GAIN || uint32_t(vr) > UNITY_GAIN)) {
+ // volume is boosted, so we might need to clamp even though
+ // we process only one track.
+ do {
+ uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
+ in += 2;
+ int32_t l = mulRL(1, rl, vrl) >> 12;
+ int32_t r = mulRL(0, rl, vrl) >> 12;
+ // clamping...
+ l = clamp16(l);
+ r = clamp16(r);
+ *out++ = (r<<16) | (l & 0xFFFF);
+ } while (--outFrames);
+ } else {
+ do {
+ uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
+ in += 2;
+ int32_t l = mulRL(1, rl, vrl) >> 12;
+ int32_t r = mulRL(0, rl, vrl) >> 12;
+ *out++ = (r<<16) | (l & 0xFFFF);
+ } while (--outFrames);
+ }
+ numFrames -= b.frameCount;
+ t.bufferProvider->releaseBuffer(&b);
+ }
}
// 2 tracks is also a common case
@@ -784,71 +822,89 @@ void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, void
i = 31 - __builtin_clz(en);
const track_t& t0 = state->tracks[i];
AudioBufferProvider::Buffer& b0(t0.buffer);
- t0.bufferProvider->getNextBuffer(&b0);
en &= ~(1<<i);
i = 31 - __builtin_clz(en);
const track_t& t1 = state->tracks[i];
AudioBufferProvider::Buffer& b1(t1.buffer);
- t1.bufferProvider->getNextBuffer(&b1);
-
+
int16_t const *in0;
const int16_t vl0 = t0.volume[0];
const int16_t vr0 = t0.volume[1];
+ size_t frameCount0 = 0;
+
int16_t const *in1;
const int16_t vl1 = t1.volume[0];
const int16_t vr1 = t1.volume[1];
- size_t numFrames = state->frameCount;
+ size_t frameCount1 = 0;
+
int32_t* out = static_cast<int32_t*>(output);
-
- // t0/1.buffer.i16 == NULL can happen if the track was flushed just after having
- // been enabled for mixing.
- if (t0.buffer.i16 != NULL) {
- in0 = t0.buffer.i16;
- if (t1.buffer.i16 != NULL) {
- in1 = t1.buffer.i16;
- } else {
- in1 = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
- memset((void *)in1, 0, state->frameCount*MAX_NUM_CHANNELS*sizeof(int16_t));
+ size_t numFrames = state->frameCount;
+ int16_t const *buff = NULL;
+
+
+ while (numFrames) {
+
+ if (frameCount0 == 0) {
+ b0.frameCount = numFrames;
+ t0.bufferProvider->getNextBuffer(&b0);
+ if (b0.i16 == NULL) {
+ if (buff == NULL) {
+ buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
+ }
+ in0 = buff;
+ b0.frameCount = numFrames;
+ } else {
+ in0 = b0.i16;
+ }
+ frameCount0 = b0.frameCount;
}
- } else {
- in0 = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
- memset((void *)in0, 0, state->frameCount*MAX_NUM_CHANNELS*sizeof(int16_t));
- if (t1.buffer.i16 != NULL) {
- in1 = t1.buffer.i16;
- } else {
- in1 = in0;
+ if (frameCount1 == 0) {
+ b1.frameCount = numFrames;
+ t1.bufferProvider->getNextBuffer(&b1);
+ if (b1.i16 == NULL) {
+ if (buff == NULL) {
+ buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
+ }
+ in1 = buff;
+ b1.frameCount = numFrames;
+ } else {
+ in1 = b1.i16;
+ }
+ frameCount1 = b1.frameCount;
}
- }
-
- do {
- int32_t l0 = *in0++;
- int32_t r0 = *in0++;
- l0 = mul(l0, vl0);
- r0 = mul(r0, vr0);
- int32_t l = *in1++;
- int32_t r = *in1++;
- l = mulAdd(l, vl1, l0) >> 12;
- r = mulAdd(r, vr1, r0) >> 12;
- // clamping...
- l = clamp16(l);
- r = clamp16(r);
- *out++ = (r<<16) | (l & 0xFFFF);
- } while (--numFrames);
+
+ size_t outFrames = frameCount0 < frameCount1?frameCount0:frameCount1;
-
- if (t0.buffer.i16 != NULL) {
- t0.bufferProvider->releaseBuffer(&b0);
- if (t1.buffer.i16 != NULL) {
- t1.bufferProvider->releaseBuffer(&b1);
- } else {
- delete [] in1;
+ numFrames -= outFrames;
+ frameCount0 -= outFrames;
+ frameCount1 -= outFrames;
+
+ do {
+ int32_t l0 = *in0++;
+ int32_t r0 = *in0++;
+ l0 = mul(l0, vl0);
+ r0 = mul(r0, vr0);
+ int32_t l = *in1++;
+ int32_t r = *in1++;
+ l = mulAdd(l, vl1, l0) >> 12;
+ r = mulAdd(r, vr1, r0) >> 12;
+ // clamping...
+ l = clamp16(l);
+ r = clamp16(r);
+ *out++ = (r<<16) | (l & 0xFFFF);
+ } while (--outFrames);
+
+ if (frameCount0 == 0) {
+ t0.bufferProvider->releaseBuffer(&b0);
}
- } else {
- delete [] in0;
- if (t1.buffer.i16 != NULL) {
+ if (frameCount1 == 0) {
t1.bufferProvider->releaseBuffer(&b1);
}
+ }
+
+ if (buff != NULL) {
+ delete [] buff;
}
}
diff --git a/libs/audioflinger/AudioMixer.h b/libs/audioflinger/AudioMixer.h
index 9ca109f..72ca28a 100644
--- a/libs/audioflinger/AudioMixer.h
+++ b/libs/audioflinger/AudioMixer.h
@@ -2,16 +2,16 @@
**
** Copyright 2007, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
@@ -130,7 +130,7 @@ private:
int32_t volumeInc[2];
- uint16_t reserved;
+ uint16_t frameCount;
uint8_t channelCount : 4;
uint8_t enabled : 1;
diff --git a/libs/audioflinger/AudioResampler.cpp b/libs/audioflinger/AudioResampler.cpp
index c93ead3..5dabacb 100644
--- a/libs/audioflinger/AudioResampler.cpp
+++ b/libs/audioflinger/AudioResampler.cpp
@@ -14,17 +14,23 @@
* limitations under the License.
*/
+#define LOG_TAG "AudioResampler"
+//#define LOG_NDEBUG 0
+
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
#include <cutils/log.h>
#include <cutils/properties.h>
-
#include "AudioResampler.h"
#include "AudioResamplerSinc.h"
#include "AudioResamplerCubic.h"
namespace android {
+
+#ifdef __ARM_ARCH_5E__ // optimized asm option
+ #define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1
+#endif // __ARM_ARCH_5E__
// ----------------------------------------------------------------------------
class AudioResamplerOrder1 : public AudioResampler {
@@ -46,6 +52,15 @@ private:
AudioBufferProvider* provider);
void resampleStereo16(int32_t* out, size_t outFrameCount,
AudioBufferProvider* provider);
+#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1
+ void AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
+ size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
+ uint32_t &phaseFraction, uint32_t phaseIncrement);
+ void AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
+ size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
+ uint32_t &phaseFraction, uint32_t phaseIncrement);
+#endif // ASM_ARM_RESAMP1
+
static inline int32_t Interp(int32_t x0, int32_t x1, uint32_t f) {
return x0 + (((x1 - x0) * (int32_t)(f >> kPreInterpShift)) >> kNumInterpBits);
}
@@ -73,20 +88,23 @@ AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount,
if (quality == DEFAULT)
quality = LOW_QUALITY;
-
+
switch (quality) {
default:
case LOW_QUALITY:
+ LOGV("Create linear Resampler");
resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate);
break;
case MED_QUALITY:
+ LOGV("Create cubic Resampler");
resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate);
break;
case HIGH_QUALITY:
+ LOGV("Create sinc Resampler");
resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate);
break;
}
-
+
// initialize resampler
resampler->init();
return resampler;
@@ -103,10 +121,10 @@ AudioResampler::AudioResampler(int bitDepth, int inChannelCount,
inChannelCount);
// LOG_ASSERT(0);
}
-
+
// initialize common members
mVolume[0] = mVolume[1] = 0;
- mBuffer.raw = NULL;
+ mBuffer.frameCount = 0;
// save format for quick lookup
if (inChannelCount == 1) {
@@ -160,19 +178,31 @@ void AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount,
uint32_t phaseIncrement = mPhaseIncrement;
size_t outputIndex = 0;
size_t outputSampleCount = outFrameCount * 2;
+ size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
// LOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d\n",
- // outFrameCount, inputIndex, phaseFraction, phaseIncrement);
+ // outFrameCount, inputIndex, phaseFraction, phaseIncrement);
while (outputIndex < outputSampleCount) {
// buffer is empty, fetch a new one
- if (mBuffer.raw == NULL) {
+ while (mBuffer.frameCount == 0) {
+ mBuffer.frameCount = inFrameCount;
provider->getNextBuffer(&mBuffer);
- if (mBuffer.raw == NULL)
- break;
+ if (mBuffer.raw == NULL) {
+ goto resampleStereo16_exit;
+ }
+
// LOGE("New buffer fetched: %d frames\n", mBuffer.frameCount);
+ if (mBuffer.frameCount > inputIndex) break;
+
+ inputIndex -= mBuffer.frameCount;
+ mX0L = mBuffer.i16[mBuffer.frameCount*2-2];
+ mX0R = mBuffer.i16[mBuffer.frameCount*2-1];
+ provider->releaseBuffer(&mBuffer);
+ // mBuffer.frameCount == 0 now so we reload a new buffer
}
+
int16_t *in = mBuffer.i16;
// handle boundary case
@@ -187,34 +217,47 @@ void AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount,
// process input samples
// LOGE("general case\n");
- while (outputIndex < outputSampleCount) {
+
+#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1
+ if (inputIndex + 2 < mBuffer.frameCount) {
+ int32_t* maxOutPt;
+ int32_t maxInIdx;
+
+ maxOutPt = out + (outputSampleCount - 2); // 2 because 2 frames per loop
+ maxInIdx = mBuffer.frameCount - 2;
+ AsmStereo16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr,
+ phaseFraction, phaseIncrement);
+ }
+#endif // ASM_ARM_RESAMP1
+
+ while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) {
out[outputIndex++] += vl * Interp(in[inputIndex*2-2],
in[inputIndex*2], phaseFraction);
out[outputIndex++] += vr * Interp(in[inputIndex*2-1],
in[inputIndex*2+1], phaseFraction);
Advance(&inputIndex, &phaseFraction, phaseIncrement);
- if (inputIndex >= mBuffer.frameCount)
- break;
}
+
// LOGE("loop done - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
// if done with buffer, save samples
if (inputIndex >= mBuffer.frameCount) {
inputIndex -= mBuffer.frameCount;
- // LOGE("buffer done, new input index", inputIndex);
+ // LOGE("buffer done, new input index %d", inputIndex);
mX0L = mBuffer.i16[mBuffer.frameCount*2-2];
mX0R = mBuffer.i16[mBuffer.frameCount*2-1];
provider->releaseBuffer(&mBuffer);
- // verify that the releaseBuffer NULLS the buffer pointer
- // LOG_ASSERT(mBuffer.raw == NULL);
+ // verify that the releaseBuffer resets the buffer frameCount
+ // LOG_ASSERT(mBuffer.frameCount == 0);
}
}
// LOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+resampleStereo16_exit:
// save state
mInputIndex = inputIndex;
mPhaseFraction = phaseFraction;
@@ -231,18 +274,27 @@ void AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount,
uint32_t phaseIncrement = mPhaseIncrement;
size_t outputIndex = 0;
size_t outputSampleCount = outFrameCount * 2;
+ size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
// LOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d\n",
// outFrameCount, inputIndex, phaseFraction, phaseIncrement);
-
while (outputIndex < outputSampleCount) {
-
// buffer is empty, fetch a new one
- if (mBuffer.raw == NULL) {
+ while (mBuffer.frameCount == 0) {
+ mBuffer.frameCount = inFrameCount;
provider->getNextBuffer(&mBuffer);
- if (mBuffer.raw == NULL)
- break;
+ if (mBuffer.raw == NULL) {
+ mInputIndex = inputIndex;
+ mPhaseFraction = phaseFraction;
+ goto resampleMono16_exit;
+ }
// LOGE("New buffer fetched: %d frames\n", mBuffer.frameCount);
+ if (mBuffer.frameCount > inputIndex) break;
+
+ inputIndex -= mBuffer.frameCount;
+ mX0L = mBuffer.i16[mBuffer.frameCount-1];
+ provider->releaseBuffer(&mBuffer);
+ // mBuffer.frameCount == 0 now so we reload a new buffer
}
int16_t *in = mBuffer.i16;
@@ -259,38 +311,284 @@ void AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount,
// process input samples
// LOGE("general case\n");
- while (outputIndex < outputSampleCount) {
+
+#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1
+ if (inputIndex + 2 < mBuffer.frameCount) {
+ int32_t* maxOutPt;
+ int32_t maxInIdx;
+
+ maxOutPt = out + (outputSampleCount - 2);
+ maxInIdx = (int32_t)mBuffer.frameCount - 2;
+ AsmMono16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr,
+ phaseFraction, phaseIncrement);
+ }
+#endif // ASM_ARM_RESAMP1
+
+ while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) {
int32_t sample = Interp(in[inputIndex-1], in[inputIndex],
phaseFraction);
out[outputIndex++] += vl * sample;
out[outputIndex++] += vr * sample;
Advance(&inputIndex, &phaseFraction, phaseIncrement);
- if (inputIndex >= mBuffer.frameCount)
- break;
}
+
+
// LOGE("loop done - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
// if done with buffer, save samples
if (inputIndex >= mBuffer.frameCount) {
inputIndex -= mBuffer.frameCount;
- // LOGE("buffer done, new input index", inputIndex);
+ // LOGE("buffer done, new input index %d", inputIndex);
mX0L = mBuffer.i16[mBuffer.frameCount-1];
provider->releaseBuffer(&mBuffer);
- // verify that the releaseBuffer NULLS the buffer pointer
- // LOG_ASSERT(mBuffer.raw == NULL);
+ // verify that the releaseBuffer resets the buffer frameCount
+ // LOG_ASSERT(mBuffer.frameCount == 0);
}
}
// LOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+resampleMono16_exit:
// save state
mInputIndex = inputIndex;
mPhaseFraction = phaseFraction;
}
+#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1
+
+/*******************************************************************
+*
+* AsmMono16Loop
+* asm optimized monotonic loop version; one loop is 2 frames
+* Input:
+* in : pointer on input samples
+* maxOutPt : pointer on first not filled
+* maxInIdx : index on first not used
+* outputIndex : pointer on current output index
+* out : pointer on output buffer
+* inputIndex : pointer on current input index
+* vl, vr : left and right gain
+* phaseFraction : pointer on current phase fraction
+* phaseIncrement
+* Ouput:
+* outputIndex :
+* out : updated buffer
+* inputIndex : index of next to use
+* phaseFraction : phase fraction for next interpolation
+*
+*******************************************************************/
+void AudioResamplerOrder1::AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
+ size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
+ uint32_t &phaseFraction, uint32_t phaseIncrement)
+{
+#define MO_PARAM5 "36" // offset of parameter 5 (outputIndex)
+
+ asm(
+ "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
+ // get parameters
+ " ldr r6, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction
+ " ldr r6, [r6]\n" // phaseFraction
+ " ldr r7, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex
+ " ldr r7, [r7]\n" // inputIndex
+ " ldr r8, [sp, #" MO_PARAM5 " + 4]\n" // out
+ " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex
+ " ldr r0, [r0]\n" // outputIndex
+ " add r8, r0, asl #2\n" // curOut
+ " ldr r9, [sp, #" MO_PARAM5 " + 24]\n" // phaseIncrement
+ " ldr r10, [sp, #" MO_PARAM5 " + 12]\n" // vl
+ " ldr r11, [sp, #" MO_PARAM5 " + 16]\n" // vr
+
+ // r0 pin, x0, Samp
+
+ // r1 in
+ // r2 maxOutPt
+ // r3 maxInIdx
+
+ // r4 x1, i1, i3, Out1
+ // r5 out0
+
+ // r6 frac
+ // r7 inputIndex
+ // r8 curOut
+
+ // r9 inc
+ // r10 vl
+ // r11 vr
+
+ // r12
+ // r13 sp
+ // r14
+
+ // the following loop works on 2 frames
+
+ ".Y4L01:\n"
+ " cmp r8, r2\n" // curOut - maxCurOut
+ " bcs .Y4L02\n"
+
+#define MO_ONE_FRAME \
+ " add r0, r1, r7, asl #1\n" /* in + inputIndex */\
+ " ldrsh r4, [r0]\n" /* in[inputIndex] */\
+ " ldr r5, [r8]\n" /* out[outputIndex] */\
+ " ldrsh r0, [r0, #-2]\n" /* in[inputIndex-1] */\
+ " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\
+ " sub r4, r4, r0\n" /* in[inputIndex] - in[inputIndex-1] */\
+ " mov r4, r4, lsl #2\n" /* <<2 */\
+ " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\
+ " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\
+ " add r0, r0, r4\n" /* x0 - (..) */\
+ " mla r5, r0, r10, r5\n" /* vl*interp + out[] */\
+ " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\
+ " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\
+ " mla r4, r0, r11, r4\n" /* vr*interp + out[] */\
+ " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */\
+ " str r4, [r8], #4\n" /* out[outputIndex++] = ... */
+
+ MO_ONE_FRAME // frame 1
+ MO_ONE_FRAME // frame 2
+
+ " cmp r7, r3\n" // inputIndex - maxInIdx
+ " bcc .Y4L01\n"
+ ".Y4L02:\n"
+
+ " bic r6, r6, #0xC0000000\n" // phaseFraction & ...
+ // save modified values
+ " ldr r0, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction
+ " str r6, [r0]\n" // phaseFraction
+ " ldr r0, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex
+ " str r7, [r0]\n" // inputIndex
+ " ldr r0, [sp, #" MO_PARAM5 " + 4]\n" // out
+ " sub r8, r0\n" // curOut - out
+ " asr r8, #2\n" // new outputIndex
+ " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex
+ " str r8, [r0]\n" // save outputIndex
+
+ " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}\n"
+ );
+}
+
+/*******************************************************************
+*
+* AsmStereo16Loop
+* asm optimized stereo loop version; one loop is 2 frames
+* Input:
+* in : pointer on input samples
+* maxOutPt : pointer on first not filled
+* maxInIdx : index on first not used
+* outputIndex : pointer on current output index
+* out : pointer on output buffer
+* inputIndex : pointer on current input index
+* vl, vr : left and right gain
+* phaseFraction : pointer on current phase fraction
+* phaseIncrement
+* Ouput:
+* outputIndex :
+* out : updated buffer
+* inputIndex : index of next to use
+* phaseFraction : phase fraction for next interpolation
+*
+*******************************************************************/
+void AudioResamplerOrder1::AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
+ size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
+ uint32_t &phaseFraction, uint32_t phaseIncrement)
+{
+#define ST_PARAM5 "40" // offset of parameter 5 (outputIndex)
+ asm(
+ "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr}\n"
+ // get parameters
+ " ldr r6, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction
+ " ldr r6, [r6]\n" // phaseFraction
+ " ldr r7, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex
+ " ldr r7, [r7]\n" // inputIndex
+ " ldr r8, [sp, #" ST_PARAM5 " + 4]\n" // out
+ " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex
+ " ldr r0, [r0]\n" // outputIndex
+ " add r8, r0, asl #2\n" // curOut
+ " ldr r9, [sp, #" ST_PARAM5 " + 24]\n" // phaseIncrement
+ " ldr r10, [sp, #" ST_PARAM5 " + 12]\n" // vl
+ " ldr r11, [sp, #" ST_PARAM5 " + 16]\n" // vr
+
+ // r0 pin, x0, Samp
+
+ // r1 in
+ // r2 maxOutPt
+ // r3 maxInIdx
+
+ // r4 x1, i1, i3, out1
+ // r5 out0
+
+ // r6 frac
+ // r7 inputIndex
+ // r8 curOut
+
+ // r9 inc
+ // r10 vl
+ // r11 vr
+
+ // r12 temporary
+ // r13 sp
+ // r14
+
+ ".Y5L01:\n"
+ " cmp r8, r2\n" // curOut - maxCurOut
+ " bcs .Y5L02\n"
+
+#define ST_ONE_FRAME \
+ " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\
+\
+ " add r0, r1, r7, asl #2\n" /* in + 2*inputIndex */\
+\
+ " ldrsh r4, [r0]\n" /* in[2*inputIndex] */\
+ " ldr r5, [r8]\n" /* out[outputIndex] */\
+ " ldrsh r12, [r0, #-4]\n" /* in[2*inputIndex-2] */\
+ " sub r4, r4, r12\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\
+ " mov r4, r4, lsl #2\n" /* <<2 */\
+ " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\
+ " add r12, r12, r4\n" /* x0 - (..) */\
+ " mla r5, r12, r10, r5\n" /* vl*interp + out[] */\
+ " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\
+ " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\
+\
+ " ldrsh r12, [r0, #+2]\n" /* in[2*inputIndex+1] */\
+ " ldrsh r0, [r0, #-2]\n" /* in[2*inputIndex-1] */\
+ " sub r12, r12, r0\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\
+ " mov r12, r12, lsl #2\n" /* <<2 */\
+ " smulwt r12, r12, r6\n" /* (x1-x0)*.. */\
+ " add r12, r0, r12\n" /* x0 - (..) */\
+ " mla r4, r12, r11, r4\n" /* vr*interp + out[] */\
+ " str r4, [r8], #4\n" /* out[outputIndex++] = ... */\
+\
+ " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\
+ " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */
+
+ ST_ONE_FRAME // frame 1
+ ST_ONE_FRAME // frame 1
+
+ " cmp r7, r3\n" // inputIndex - maxInIdx
+ " bcc .Y5L01\n"
+ ".Y5L02:\n"
+
+ " bic r6, r6, #0xC0000000\n" // phaseFraction & ...
+ // save modified values
+ " ldr r0, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction
+ " str r6, [r0]\n" // phaseFraction
+ " ldr r0, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex
+ " str r7, [r0]\n" // inputIndex
+ " ldr r0, [sp, #" ST_PARAM5 " + 4]\n" // out
+ " sub r8, r0\n" // curOut - out
+ " asr r8, #2\n" // new outputIndex
+ " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex
+ " str r8, [r0]\n" // save outputIndex
+
+ " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, pc}\n"
+ );
+}
+
+#endif // ASM_ARM_RESAMP1
+
+
// ----------------------------------------------------------------------------
}
; // namespace android
diff --git a/libs/audioflinger/AudioResamplerCubic.cpp b/libs/audioflinger/AudioResamplerCubic.cpp
index 4f437bf..1d247bd 100644
--- a/libs/audioflinger/AudioResamplerCubic.cpp
+++ b/libs/audioflinger/AudioResamplerCubic.cpp
@@ -60,9 +60,11 @@ void AudioResamplerCubic::resampleStereo16(int32_t* out, size_t outFrameCount,
uint32_t phaseIncrement = mPhaseIncrement;
size_t outputIndex = 0;
size_t outputSampleCount = outFrameCount * 2;
-
+ size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
+
// fetch first buffer
- if (mBuffer.raw == NULL) {
+ if (mBuffer.frameCount == 0) {
+ mBuffer.frameCount = inFrameCount;
provider->getNextBuffer(&mBuffer);
if (mBuffer.raw == NULL)
return;
@@ -79,7 +81,7 @@ void AudioResamplerCubic::resampleStereo16(int32_t* out, size_t outFrameCount,
out[outputIndex++] += vl * interp(&left, x);
out[outputIndex++] += vr * interp(&right, x);
// out[outputIndex++] += vr * in[inputIndex*2];
-
+
// increment phase
phaseFraction += phaseIncrement;
uint32_t indexIncrement = (phaseFraction >> kNumPhaseBits);
@@ -92,6 +94,7 @@ void AudioResamplerCubic::resampleStereo16(int32_t* out, size_t outFrameCount,
if (inputIndex == mBuffer.frameCount) {
inputIndex = 0;
provider->releaseBuffer(&mBuffer);
+ mBuffer.frameCount = inFrameCount;
provider->getNextBuffer(&mBuffer);
if (mBuffer.raw == NULL)
goto save_state; // ugly, but efficient
@@ -122,9 +125,11 @@ void AudioResamplerCubic::resampleMono16(int32_t* out, size_t outFrameCount,
uint32_t phaseIncrement = mPhaseIncrement;
size_t outputIndex = 0;
size_t outputSampleCount = outFrameCount * 2;
-
+ size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
+
// fetch first buffer
- if (mBuffer.raw == NULL) {
+ if (mBuffer.frameCount == 0) {
+ mBuffer.frameCount = inFrameCount;
provider->getNextBuffer(&mBuffer);
if (mBuffer.raw == NULL)
return;
@@ -141,7 +146,7 @@ void AudioResamplerCubic::resampleMono16(int32_t* out, size_t outFrameCount,
sample = interp(&left, x);
out[outputIndex++] += vl * sample;
out[outputIndex++] += vr * sample;
-
+
// increment phase
phaseFraction += phaseIncrement;
uint32_t indexIncrement = (phaseFraction >> kNumPhaseBits);
@@ -154,6 +159,7 @@ void AudioResamplerCubic::resampleMono16(int32_t* out, size_t outFrameCount,
if (inputIndex == mBuffer.frameCount) {
inputIndex = 0;
provider->releaseBuffer(&mBuffer);
+ mBuffer.frameCount = inFrameCount;
provider->getNextBuffer(&mBuffer);
if (mBuffer.raw == NULL)
goto save_state; // ugly, but efficient
diff --git a/libs/audioflinger/AudioResamplerSinc.cpp b/libs/audioflinger/AudioResamplerSinc.cpp
index e710d16..9e5e254 100644
--- a/libs/audioflinger/AudioResamplerSinc.cpp
+++ b/libs/audioflinger/AudioResamplerSinc.cpp
@@ -25,18 +25,18 @@ namespace android {
* These coeficients are computed with the "fir" utility found in
* tools/resampler_tools
* TODO: A good optimization would be to transpose this matrix, to take
- * better advantage of the data-cache.
+ * better advantage of the data-cache.
*/
const int32_t AudioResamplerSinc::mFirCoefsUp[] = {
- 0x7fffffff, 0x7f15d078, 0x7c5e0da6, 0x77ecd867, 0x71e2e251, 0x6a6c304a, 0x61be7269, 0x58170412, 0x4db8ab05, 0x42e92ea6, 0x37eee214, 0x2d0e3bb1, 0x22879366, 0x18951e95, 0x0f693d0d, 0x072d2621,
- 0x00000000, 0xf9f66655, 0xf51a5fd7, 0xf16bbd84, 0xeee0d9ac, 0xed67a922, 0xece70de6, 0xed405897, 0xee50e505, 0xeff3be30, 0xf203370f, 0xf45a6741, 0xf6d67d53, 0xf957db66, 0xfbc2f647, 0xfe00f2b9,
- 0x00000000, 0x01b37218, 0x0313a0c6, 0x041d930d, 0x04d28057, 0x053731b0, 0x05534dff, 0x05309bfd, 0x04da440d, 0x045c1aee, 0x03c1fcdd, 0x03173ef5, 0x02663ae8, 0x01b7f736, 0x0113ec79, 0x007fe6a9,
- 0x00000000, 0xff96b229, 0xff44f99f, 0xff0a86be, 0xfee5f803, 0xfed518fd, 0xfed521fd, 0xfee2f4fd, 0xfefb54f8, 0xff1b159b, 0xff3f4203, 0xff6539e0, 0xff8ac502, 0xffae1ddd, 0xffcdf3f9, 0xffe96798,
- 0x00000000, 0x00119de6, 0x001e6b7e, 0x0026cb7a, 0x002b4830, 0x002c83d6, 0x002b2a82, 0x0027e67a, 0x002356f9, 0x001e098e, 0x001875e4, 0x0012fbbe, 0x000de2d1, 0x00095c10, 0x00058414, 0x00026636,
- 0x00000000, 0xfffe44a9, 0xfffd206d, 0xfffc7b7f, 0xfffc3c8f, 0xfffc4ac2, 0xfffc8f2b, 0xfffcf5c4, 0xfffd6df3, 0xfffdeab2, 0xfffe6275, 0xfffececf, 0xffff2c07, 0xffff788c, 0xffffb471, 0xffffe0f2,
- 0x00000000, 0x000013e6, 0x00001f03, 0x00002396, 0x00002399, 0x000020b6, 0x00001c3c, 0x00001722, 0x00001216, 0x00000d81, 0x0000099c, 0x0000067c, 0x00000419, 0x0000025f, 0x00000131, 0x00000070,
- 0x00000000, 0xffffffc7, 0xffffffb3, 0xffffffb3, 0xffffffbe, 0xffffffcd, 0xffffffdb, 0xffffffe7, 0xfffffff0, 0xfffffff7, 0xfffffffb, 0xfffffffe, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000 // this one is needed for lerping the last coefficient
+ 0x7fffffff, 0x7f15d078, 0x7c5e0da6, 0x77ecd867, 0x71e2e251, 0x6a6c304a, 0x61be7269, 0x58170412, 0x4db8ab05, 0x42e92ea6, 0x37eee214, 0x2d0e3bb1, 0x22879366, 0x18951e95, 0x0f693d0d, 0x072d2621,
+ 0x00000000, 0xf9f66655, 0xf51a5fd7, 0xf16bbd84, 0xeee0d9ac, 0xed67a922, 0xece70de6, 0xed405897, 0xee50e505, 0xeff3be30, 0xf203370f, 0xf45a6741, 0xf6d67d53, 0xf957db66, 0xfbc2f647, 0xfe00f2b9,
+ 0x00000000, 0x01b37218, 0x0313a0c6, 0x041d930d, 0x04d28057, 0x053731b0, 0x05534dff, 0x05309bfd, 0x04da440d, 0x045c1aee, 0x03c1fcdd, 0x03173ef5, 0x02663ae8, 0x01b7f736, 0x0113ec79, 0x007fe6a9,
+ 0x00000000, 0xff96b229, 0xff44f99f, 0xff0a86be, 0xfee5f803, 0xfed518fd, 0xfed521fd, 0xfee2f4fd, 0xfefb54f8, 0xff1b159b, 0xff3f4203, 0xff6539e0, 0xff8ac502, 0xffae1ddd, 0xffcdf3f9, 0xffe96798,
+ 0x00000000, 0x00119de6, 0x001e6b7e, 0x0026cb7a, 0x002b4830, 0x002c83d6, 0x002b2a82, 0x0027e67a, 0x002356f9, 0x001e098e, 0x001875e4, 0x0012fbbe, 0x000de2d1, 0x00095c10, 0x00058414, 0x00026636,
+ 0x00000000, 0xfffe44a9, 0xfffd206d, 0xfffc7b7f, 0xfffc3c8f, 0xfffc4ac2, 0xfffc8f2b, 0xfffcf5c4, 0xfffd6df3, 0xfffdeab2, 0xfffe6275, 0xfffececf, 0xffff2c07, 0xffff788c, 0xffffb471, 0xffffe0f2,
+ 0x00000000, 0x000013e6, 0x00001f03, 0x00002396, 0x00002399, 0x000020b6, 0x00001c3c, 0x00001722, 0x00001216, 0x00000d81, 0x0000099c, 0x0000067c, 0x00000419, 0x0000025f, 0x00000131, 0x00000070,
+ 0x00000000, 0xffffffc7, 0xffffffb3, 0xffffffb3, 0xffffffbe, 0xffffffcd, 0xffffffdb, 0xffffffe7, 0xfffffff0, 0xfffffff7, 0xfffffffb, 0xfffffffe, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000 // this one is needed for lerping the last coefficient
};
/*
@@ -46,20 +46,20 @@ const int32_t AudioResamplerSinc::mFirCoefsUp[] = {
* these coefficient from the above by "Stretching" them in time).
*/
const int32_t AudioResamplerSinc::mFirCoefsDown[] = {
- 0x7fffffff, 0x7f55e46d, 0x7d5b4c60, 0x7a1b4b98, 0x75a7fb14, 0x7019f0bd, 0x698f875a, 0x622bfd59, 0x5a167256, 0x5178cc54, 0x487e8e6c, 0x3f53aae8, 0x36235ad4, 0x2d17047b, 0x245539ab, 0x1c00d540,
- 0x14383e57, 0x0d14d5ca, 0x06aa910b, 0x0107c38b, 0xfc351654, 0xf835abae, 0xf5076b45, 0xf2a37202, 0xf0fe9faa, 0xf00a3bbd, 0xefb4aa81, 0xefea2b05, 0xf0959716, 0xf1a11e83, 0xf2f6f7a0, 0xf481fff4,
- 0xf62e48ce, 0xf7e98ca5, 0xf9a38b4c, 0xfb4e4bfa, 0xfcde456f, 0xfe4a6d30, 0xff8c2fdf, 0x009f5555, 0x0181d393, 0x0233940f, 0x02b62f06, 0x030ca07d, 0x033afa62, 0x03461725, 0x03334f83, 0x030835fa,
- 0x02ca59cc, 0x027f12d1, 0x022b570d, 0x01d39a49, 0x017bb78f, 0x0126e414, 0x00d7aaaf, 0x008feec7, 0x0050f584, 0x001b73e3, 0xffefa063, 0xffcd46ed, 0xffb3ddcd, 0xffa29aaa, 0xff988691, 0xff949066,
- 0xff959d24, 0xff9a959e, 0xffa27195, 0xffac4011, 0xffb72d2b, 0xffc28569, 0xffcdb706, 0xffd85171, 0xffe20364, 0xffea97e9, 0xfff1f2b2, 0xfff80c06, 0xfffcec92, 0x0000a955, 0x00035fd8, 0x000532cf,
- 0x00064735, 0x0006c1f9, 0x0006c62d, 0x000673ba, 0x0005e68f, 0x00053630, 0x000475a3, 0x0003b397, 0x0002fac1, 0x00025257, 0x0001be9e, 0x0001417a, 0x0000dafd, 0x000089eb, 0x00004c28, 0x00001f1d,
- 0x00000000, 0xffffec10, 0xffffe0be, 0xffffdbc5, 0xffffdb39, 0xffffdd8b, 0xffffe182, 0xffffe638, 0xffffeb0a, 0xffffef8f, 0xfffff38b, 0xfffff6e3, 0xfffff993, 0xfffffba6, 0xfffffd30, 0xfffffe4a,
- 0xffffff09, 0xffffff85, 0xffffffd1, 0xfffffffb, 0x0000000f, 0x00000016, 0x00000015, 0x00000012, 0x0000000d, 0x00000009, 0x00000006, 0x00000003, 0x00000002, 0x00000001, 0x00000000, 0x00000000,
- 0x00000000 // this one is needed for lerping the last coefficient
+ 0x7fffffff, 0x7f55e46d, 0x7d5b4c60, 0x7a1b4b98, 0x75a7fb14, 0x7019f0bd, 0x698f875a, 0x622bfd59, 0x5a167256, 0x5178cc54, 0x487e8e6c, 0x3f53aae8, 0x36235ad4, 0x2d17047b, 0x245539ab, 0x1c00d540,
+ 0x14383e57, 0x0d14d5ca, 0x06aa910b, 0x0107c38b, 0xfc351654, 0xf835abae, 0xf5076b45, 0xf2a37202, 0xf0fe9faa, 0xf00a3bbd, 0xefb4aa81, 0xefea2b05, 0xf0959716, 0xf1a11e83, 0xf2f6f7a0, 0xf481fff4,
+ 0xf62e48ce, 0xf7e98ca5, 0xf9a38b4c, 0xfb4e4bfa, 0xfcde456f, 0xfe4a6d30, 0xff8c2fdf, 0x009f5555, 0x0181d393, 0x0233940f, 0x02b62f06, 0x030ca07d, 0x033afa62, 0x03461725, 0x03334f83, 0x030835fa,
+ 0x02ca59cc, 0x027f12d1, 0x022b570d, 0x01d39a49, 0x017bb78f, 0x0126e414, 0x00d7aaaf, 0x008feec7, 0x0050f584, 0x001b73e3, 0xffefa063, 0xffcd46ed, 0xffb3ddcd, 0xffa29aaa, 0xff988691, 0xff949066,
+ 0xff959d24, 0xff9a959e, 0xffa27195, 0xffac4011, 0xffb72d2b, 0xffc28569, 0xffcdb706, 0xffd85171, 0xffe20364, 0xffea97e9, 0xfff1f2b2, 0xfff80c06, 0xfffcec92, 0x0000a955, 0x00035fd8, 0x000532cf,
+ 0x00064735, 0x0006c1f9, 0x0006c62d, 0x000673ba, 0x0005e68f, 0x00053630, 0x000475a3, 0x0003b397, 0x0002fac1, 0x00025257, 0x0001be9e, 0x0001417a, 0x0000dafd, 0x000089eb, 0x00004c28, 0x00001f1d,
+ 0x00000000, 0xffffec10, 0xffffe0be, 0xffffdbc5, 0xffffdb39, 0xffffdd8b, 0xffffe182, 0xffffe638, 0xffffeb0a, 0xffffef8f, 0xfffff38b, 0xfffff6e3, 0xfffff993, 0xfffffba6, 0xfffffd30, 0xfffffe4a,
+ 0xffffff09, 0xffffff85, 0xffffffd1, 0xfffffffb, 0x0000000f, 0x00000016, 0x00000015, 0x00000012, 0x0000000d, 0x00000009, 0x00000006, 0x00000003, 0x00000002, 0x00000001, 0x00000000, 0x00000000,
+ 0x00000000 // this one is needed for lerping the last coefficient
};
// ----------------------------------------------------------------------------
-static inline
+static inline
int32_t mulRL(int left, int32_t in, uint32_t vRL)
{
#if defined(__arm__) && !defined(__thumb__)
@@ -85,7 +85,7 @@ int32_t mulRL(int left, int32_t in, uint32_t vRL)
#endif
}
-static inline
+static inline
int32_t mulAdd(int16_t in, int32_t v, int32_t a)
{
#if defined(__arm__) && !defined(__thumb__)
@@ -95,12 +95,14 @@ int32_t mulAdd(int16_t in, int32_t v, int32_t a)
: [in]"%r"(in), [v]"r"(v), [a]"r"(a)
: );
return out;
-#else
- return a + ((in * int32_t(v))>>16);
+#else
+ return a + in * (v>>16);
+ // improved precision
+ // return a + in * (v>>16) + ((in * (v & 0xffff)) >> 16);
#endif
}
-static inline
+static inline
int32_t mulAddRL(int left, uint32_t inRL, int32_t v, int32_t a)
{
#if defined(__arm__) && !defined(__thumb__)
@@ -119,9 +121,11 @@ int32_t mulAddRL(int left, uint32_t inRL, int32_t v, int32_t a)
return out;
#else
if (left) {
- return a + ((int16_t(inRL&0xFFFF) * int32_t(v))>>16);
+ return a + (int16_t(inRL&0xFFFF) * (v>>16));
+ //improved precision
+ // return a + (int16_t(inRL&0xFFFF) * (v>>16)) + ((int16_t(inRL&0xFFFF) * (v & 0xffff)) >> 16);
} else {
- return a + ((int16_t(inRL>>16) * int32_t(v))>>16);
+ return a + (int16_t(inRL>>16) * (v>>16));
}
#endif
}
@@ -129,37 +133,37 @@ int32_t mulAddRL(int left, uint32_t inRL, int32_t v, int32_t a)
// ----------------------------------------------------------------------------
AudioResamplerSinc::AudioResamplerSinc(int bitDepth,
- int inChannelCount, int32_t sampleRate)
- : AudioResampler(bitDepth, inChannelCount, sampleRate),
- mState(0)
+ int inChannelCount, int32_t sampleRate)
+ : AudioResampler(bitDepth, inChannelCount, sampleRate),
+ mState(0)
{
- /*
- * Layout of the state buffer for 32 tap:
- *
- * "present" sample beginning of 2nd buffer
- * v v
- * 0 01 2 23 3
- * 0 F0 0 F0 F
- * [pppppppppppppppInnnnnnnnnnnnnnnnpppppppppppppppInnnnnnnnnnnnnnnn]
- * ^ ^ head
- *
- * p = past samples, convoluted with the (p)ositive side of sinc()
- * n = future samples, convoluted with the (n)egative side of sinc()
- * r = extra space for implementing the ring buffer
- *
- */
+ /*
+ * Layout of the state buffer for 32 tap:
+ *
+ * "present" sample beginning of 2nd buffer
+ * v v
+ * 0 01 2 23 3
+ * 0 F0 0 F0 F
+ * [pppppppppppppppInnnnnnnnnnnnnnnnpppppppppppppppInnnnnnnnnnnnnnnn]
+ * ^ ^ head
+ *
+ * p = past samples, convoluted with the (p)ositive side of sinc()
+ * n = future samples, convoluted with the (n)egative side of sinc()
+ * r = extra space for implementing the ring buffer
+ *
+ */
- const size_t numCoefs = 2*halfNumCoefs;
- const size_t stateSize = numCoefs * inChannelCount * 2;
- mState = new int16_t[stateSize];
- memset(mState, 0, sizeof(int16_t)*stateSize);
- mImpulse = mState + (halfNumCoefs-1)*inChannelCount;
- mRingFull = mImpulse + (numCoefs+1)*inChannelCount;
+ const size_t numCoefs = 2*halfNumCoefs;
+ const size_t stateSize = numCoefs * inChannelCount * 2;
+ mState = new int16_t[stateSize];
+ memset(mState, 0, sizeof(int16_t)*stateSize);
+ mImpulse = mState + (halfNumCoefs-1)*inChannelCount;
+ mRingFull = mImpulse + (numCoefs+1)*inChannelCount;
}
AudioResamplerSinc::~AudioResamplerSinc()
{
- delete [] mState;
+ delete [] mState;
}
void AudioResamplerSinc::init() {
@@ -168,9 +172,9 @@ void AudioResamplerSinc::init() {
void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
AudioBufferProvider* provider)
{
- mFirCoefs = (mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown;
+ mFirCoefs = (mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown;
- // select the appropriate resampler
+ // select the appropriate resampler
switch (mChannelCount) {
case 1:
resample<1>(out, outFrameCount, provider);
@@ -193,43 +197,68 @@ void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
uint32_t phaseIncrement = mPhaseIncrement;
size_t outputIndex = 0;
size_t outputSampleCount = outFrameCount * 2;
+ size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
AudioBufferProvider::Buffer& buffer(mBuffer);
while (outputIndex < outputSampleCount) {
// buffer is empty, fetch a new one
- if (buffer.raw == NULL) {
+ while (buffer.frameCount == 0) {
+ buffer.frameCount = inFrameCount;
provider->getNextBuffer(&buffer);
- if (buffer.raw == NULL)
- break;
- const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
- if (phaseIndex) {
- read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+ if (buffer.raw == NULL) {
+ goto resample_exit;
}
+ const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
+ if (phaseIndex == 1) {
+ // read one frame
+ read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+ } else if (phaseIndex == 2) {
+ // read 2 frames
+ read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+ inputIndex++;
+ if (inputIndex >= mBuffer.frameCount) {
+ inputIndex -= mBuffer.frameCount;
+ provider->releaseBuffer(&buffer);
+ } else {
+ read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+ }
+ }
}
int16_t *in = buffer.i16;
- const size_t frameCount = buffer.frameCount;
+ const size_t frameCount = buffer.frameCount;
- // Always read-in the first samples from the input buffer
- int16_t* head = impulse + halfNumCoefs*CHANNELS;
- head[0] = in[inputIndex*CHANNELS + 0];
- if (CHANNELS == 2)
- head[1] = in[inputIndex*CHANNELS + 1];
+ // Always read-in the first samples from the input buffer
+ int16_t* head = impulse + halfNumCoefs*CHANNELS;
+ head[0] = in[inputIndex*CHANNELS + 0];
+ if (CHANNELS == 2)
+ head[1] = in[inputIndex*CHANNELS + 1];
// handle boundary case
- int32_t l, r;
+ int32_t l, r;
while (outputIndex < outputSampleCount) {
- filterCoefficient<CHANNELS>(l, r, phaseFraction, impulse);
- out[outputIndex++] = mulRL(1, l, vRL);
- out[outputIndex++] = mulRL(0, r, vRL);
+ filterCoefficient<CHANNELS>(l, r, phaseFraction, impulse);
+ out[outputIndex++] += 2 * mulRL(1, l, vRL);
+ out[outputIndex++] += 2 * mulRL(0, r, vRL);
- phaseFraction += phaseIncrement;
- const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
- if (phaseIndex) {
- inputIndex += phaseIndex;
- if (inputIndex >= frameCount)
- break;
- read<CHANNELS>(impulse, phaseFraction, in, inputIndex);
- }
+ phaseFraction += phaseIncrement;
+ const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
+ if (phaseIndex == 1) {
+ inputIndex++;
+ if (inputIndex >= frameCount)
+ break; // need a new buffer
+ read<CHANNELS>(impulse, phaseFraction, in, inputIndex);
+ } else if(phaseIndex == 2) { // maximum value
+ inputIndex++;
+ if (inputIndex >= frameCount)
+ break; // 0 frame available, 2 frames needed
+ // read first frame
+ read<CHANNELS>(impulse, phaseFraction, in, inputIndex);
+ inputIndex++;
+ if (inputIndex >= frameCount)
+ break; // 0 frame available, 1 frame needed
+ // read second frame
+ read<CHANNELS>(impulse, phaseFraction, in, inputIndex);
+ }
}
// if done with buffer, save samples
@@ -239,80 +268,89 @@ void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
}
}
+resample_exit:
mImpulse = impulse;
mInputIndex = inputIndex;
mPhaseFraction = phaseFraction;
}
template<int CHANNELS>
+/***
+* read()
+*
+* This function reads only one frame from input buffer and writes it in
+* state buffer
+*
+**/
void AudioResamplerSinc::read(
- int16_t*& impulse, uint32_t& phaseFraction,
- int16_t const* in, size_t inputIndex)
+ int16_t*& impulse, uint32_t& phaseFraction,
+ int16_t const* in, size_t inputIndex)
{
- // read new samples into the ring buffer
- while (phaseFraction >> kNumPhaseBits) {
- const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
- impulse += CHANNELS;
- phaseFraction -= 1LU<<kNumPhaseBits;
- if (impulse >= mRingFull) {
- const size_t stateSize = (halfNumCoefs*2)*CHANNELS;
- memcpy(mState, mState+stateSize, sizeof(int16_t)*stateSize);
- impulse -= stateSize;
- }
- int16_t* head = impulse + halfNumCoefs*CHANNELS;
- head[0] = in[inputIndex*CHANNELS + 0];
- if (CHANNELS == 2)
- head[1] = in[inputIndex*CHANNELS + 1];
- }
+ const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
+ impulse += CHANNELS;
+ phaseFraction -= 1LU<<kNumPhaseBits;
+ if (impulse >= mRingFull) {
+ const size_t stateSize = (halfNumCoefs*2)*CHANNELS;
+ memcpy(mState, mState+stateSize, sizeof(int16_t)*stateSize);
+ impulse -= stateSize;
+ }
+ int16_t* head = impulse + halfNumCoefs*CHANNELS;
+ head[0] = in[inputIndex*CHANNELS + 0];
+ if (CHANNELS == 2)
+ head[1] = in[inputIndex*CHANNELS + 1];
}
template<int CHANNELS>
void AudioResamplerSinc::filterCoefficient(
- int32_t& l, int32_t& r, uint32_t phase, int16_t const *samples)
-{
- // compute the index of the coefficient on the positive side and
- // negative side
- uint32_t indexP = (phase & cMask) >> cShift;
- uint16_t lerpP = (phase & pMask) >> pShift;
- uint32_t indexN = (-phase & cMask) >> cShift;
- uint16_t lerpN = (-phase & pMask) >> pShift;
-
- l = 0;
- r = 0;
- int32_t const* coefs = mFirCoefs;
- int16_t const *sP = samples;
- int16_t const *sN = samples+CHANNELS;
- for (unsigned int i=0 ; i<halfNumCoefs/4 ; i++) {
- interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
- interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
- sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
+ int32_t& l, int32_t& r, uint32_t phase, int16_t const *samples)
+{
+ // compute the index of the coefficient on the positive side and
+ // negative side
+ uint32_t indexP = (phase & cMask) >> cShift;
+ uint16_t lerpP = (phase & pMask) >> pShift;
+ uint32_t indexN = (-phase & cMask) >> cShift;
+ uint16_t lerpN = (-phase & pMask) >> pShift;
+ if ((indexP == 0) && (lerpP == 0)) {
+ indexN = cMask >> cShift;
+ lerpN = pMask >> pShift;
+ }
+
+ l = 0;
+ r = 0;
+ int32_t const* coefs = mFirCoefs;
+ int16_t const *sP = samples;
+ int16_t const *sN = samples+CHANNELS;
+ for (unsigned int i=0 ; i<halfNumCoefs/4 ; i++) {
interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
- sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
+ sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
- sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
+ sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
- sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
- }
+ sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
+ interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
+ interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
+ sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
+ }
}
template<int CHANNELS>
void AudioResamplerSinc::interpolate(
int32_t& l, int32_t& r,
- int32_t const* coefs, int16_t lerp, int16_t const* samples)
+ int32_t const* coefs, int16_t lerp, int16_t const* samples)
{
- int32_t c0 = coefs[0];
- int32_t c1 = coefs[1];
- int32_t sinc = mulAdd(lerp, (c1-c0)<<1, c0);
- if (CHANNELS == 2) {
- uint32_t rl = *reinterpret_cast<uint32_t const*>(samples);
- l = mulAddRL(1, rl, sinc, l);
- r = mulAddRL(0, rl, sinc, r);
- } else {
- r = l = mulAdd(samples[0], sinc, l);
- }
+ int32_t c0 = coefs[0];
+ int32_t c1 = coefs[1];
+ int32_t sinc = mulAdd(lerp, (c1-c0)<<1, c0);
+ if (CHANNELS == 2) {
+ uint32_t rl = *reinterpret_cast<uint32_t const*>(samples);
+ l = mulAddRL(1, rl, sinc, l);
+ r = mulAddRL(0, rl, sinc, r);
+ } else {
+ r = l = mulAdd(samples[0], sinc, l);
+ }
}
// ----------------------------------------------------------------------------
diff --git a/libs/audioflinger/AudioResamplerSinc.h b/libs/audioflinger/AudioResamplerSinc.h
index 89b9577..e6cb90b 100644
--- a/libs/audioflinger/AudioResamplerSinc.h
+++ b/libs/audioflinger/AudioResamplerSinc.h
@@ -24,19 +24,20 @@
#include "AudioResampler.h"
namespace android {
+
// ----------------------------------------------------------------------------
class AudioResamplerSinc : public AudioResampler {
public:
- AudioResamplerSinc(int bitDepth, int inChannelCount, int32_t sampleRate);
+ AudioResamplerSinc(int bitDepth, int inChannelCount, int32_t sampleRate);
+
+ ~AudioResamplerSinc();
- ~AudioResamplerSinc();
-
virtual void resample(int32_t* out, size_t outFrameCount,
AudioBufferProvider* provider);
private:
void init();
-
+
template<int CHANNELS>
void resample(int32_t* out, size_t outFrameCount,
AudioBufferProvider* provider);
@@ -52,12 +53,12 @@ private:
template<int CHANNELS>
inline void read(int16_t*& impulse, uint32_t& phaseFraction,
- int16_t const* in, size_t inputIndex);
+ int16_t const* in, size_t inputIndex);
int16_t *mState;
int16_t *mImpulse;
int16_t *mRingFull;
-
+
int32_t const * mFirCoefs;
static const int32_t mFirCoefsDown[];
static const int32_t mFirCoefsUp[];
@@ -67,15 +68,15 @@ private:
static const int32_t RESAMPLE_FIR_LERP_INT_BITS = 4;
// we have 16 coefs samples per zero-crossing
- static const int coefsBits = RESAMPLE_FIR_LERP_INT_BITS;
- static const int cShift = kNumPhaseBits - coefsBits;
- static const uint32_t cMask = ((1<<coefsBits)-1) << cShift;
+ static const int coefsBits = RESAMPLE_FIR_LERP_INT_BITS; // 4
+ static const int cShift = kNumPhaseBits - coefsBits; // 26
+ static const uint32_t cMask = ((1<<coefsBits)-1) << cShift; // 0xf<<26 = 3c00 0000
// and we use 15 bits to interpolate between these samples
// this cannot change because the mul below rely on it.
static const int pLerpBits = 15;
- static const int pShift = kNumPhaseBits - coefsBits - pLerpBits;
- static const uint32_t pMask = ((1<<pLerpBits)-1) << pShift;
+ static const int pShift = kNumPhaseBits - coefsBits - pLerpBits; // 11
+ static const uint32_t pMask = ((1<<pLerpBits)-1) << pShift; // 0x7fff << 11
// number of zero-crossing on each side
static const unsigned int halfNumCoefs = RESAMPLE_FIR_NUM_COEF;
diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk
index 7741456..d14cebf 100644
--- a/libs/surfaceflinger/Android.mk
+++ b/libs/surfaceflinger/Android.mk
@@ -31,6 +31,7 @@ ifeq ($(TARGET_SIMULATOR),true)
endif
LOCAL_SHARED_LIBRARIES := \
+ libhardware \
libutils \
libcutils \
libui \
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 5dd9446..cd72179 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -19,6 +19,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <math.h>
#include <GLES/egl.h>
@@ -27,7 +28,9 @@
#include <ui/EGLDisplaySurface.h>
#include "DisplayHardware/DisplayHardware.h"
-#include "ui/BlitHardware.h"
+
+#include <hardware/copybit.h>
+#include <hardware/overlay.h>
using namespace android;
@@ -91,19 +94,13 @@ DisplayHardware::~DisplayHardware()
fini();
}
-float DisplayHardware::getDpiX() const { return mDpiX; }
-float DisplayHardware::getDpiY() const { return mDpiY; }
-float DisplayHardware::getRefreshRate() const { return mRefreshRate; }
-
-int DisplayHardware::getWidth() const {
- return mWidth;
-}
-int DisplayHardware::getHeight() const {
- return mHeight;
-}
-PixelFormat DisplayHardware::getFormat() const {
- return mFormat;
-}
+float DisplayHardware::getDpiX() const { return mDpiX; }
+float DisplayHardware::getDpiY() const { return mDpiY; }
+float DisplayHardware::getDensity() const { return mDensity; }
+float DisplayHardware::getRefreshRate() const { return mRefreshRate; }
+int DisplayHardware::getWidth() const { return mWidth; }
+int DisplayHardware::getHeight() const { return mHeight; }
+PixelFormat DisplayHardware::getFormat() const { return mFormat; }
void DisplayHardware::init(uint32_t dpy)
{
@@ -195,6 +192,12 @@ void DisplayHardware::init(uint32_t dpy)
mDpiY = 25.4f * float(value)/EGL_DISPLAY_SCALING;
}
mRefreshRate = 60.f; // TODO: get the real refresh rate
+
+ // compute a "density" automatically as a scale factor from 160 dpi
+ // TODO: this value should be calculated a compile time based on the
+ // board.
+ mDensity = floorf((mDpiX>mDpiY ? mDpiX : mDpiY)*0.1f + 0.5f) * (10.0f/160.0f);
+ LOGI("density = %f", mDensity);
/*
* Create our OpenGL ES context
@@ -237,8 +240,18 @@ void DisplayHardware::init(uint32_t dpy)
mSurface = surface;
mContext = context;
mFormat = GGL_PIXEL_FORMAT_RGB_565;
+
+ hw_module_t const* module;
- mBlitEngine = copybit_init();
+ mBlitEngine = NULL;
+ if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
+ copybit_open(module, &mBlitEngine);
+ }
+
+ mOverlayEngine = NULL;
+ if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
+ overlay_open(module, &mOverlayEngine);
+ }
}
/*
@@ -252,7 +265,8 @@ void DisplayHardware::fini()
{
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglTerminate(mDisplay);
- copybit_term(mBlitEngine);
+ copybit_close(mBlitEngine);
+ overlay_close(mOverlayEngine);
}
void DisplayHardware::releaseScreen() const
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
index 299e236..de4a2cc 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -26,6 +26,8 @@
#include "DisplayHardware/DisplayHardwareBase.h"
+struct overlay_device_t;
+struct copybit_device_t;
struct copybit_image_t;
struct copybit_t;
@@ -64,6 +66,7 @@ public:
float getDpiX() const;
float getDpiY() const;
float getRefreshRate() const;
+ float getDensity() const;
int getWidth() const;
int getHeight() const;
PixelFormat getFormat() const;
@@ -74,7 +77,8 @@ public:
void getDisplaySurface(copybit_image_t* img) const;
void getDisplaySurface(GGLSurface* fb) const;
EGLDisplay getEGLDisplay() const { return mDisplay; }
- copybit_t* getBlitEngine() const { return mBlitEngine; }
+ copybit_device_t* getBlitEngine() const { return mBlitEngine; }
+ overlay_device_t* getOverlayEngine() const { return mOverlayEngine; }
Rect bounds() const {
return Rect(mWidth, mHeight);
@@ -91,13 +95,15 @@ private:
float mDpiX;
float mDpiY;
float mRefreshRate;
+ float mDensity;
int mWidth;
int mHeight;
PixelFormat mFormat;
uint32_t mFlags;
mutable Region mDirty;
sp<EGLDisplaySurface> mDisplaySurface;
- copybit_t* mBlitEngine;
+ copybit_device_t* mBlitEngine;
+ overlay_device_t* mOverlayEngine;
};
}; // namespace android
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
index 90f6287..f75e5c2 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
@@ -49,8 +49,10 @@
// ----------------------------------------------------------------------------
namespace android {
-static char const * const kSleepFileName = "/sys/android_power/wait_for_fb_sleep";
-static char const * const kWakeFileName = "/sys/android_power/wait_for_fb_wake";
+static char const * kSleepFileName = "/sys/power/wait_for_fb_sleep";
+static char const * kWakeFileName = "/sys/power/wait_for_fb_wake";
+static char const * const kOldSleepFileName = "/sys/android_power/wait_for_fb_sleep";
+static char const * const kOldWakeFileName = "/sys/android_power/wait_for_fb_wake";
// This dir exists if the framebuffer console is present, either built into
// the kernel or loaded as a module.
@@ -123,16 +125,22 @@ status_t DisplayHardwareBase::DisplayEventThread::releaseScreen() const
status_t DisplayHardwareBase::DisplayEventThread::readyToRun()
{
if (access(kSleepFileName, R_OK) || access(kWakeFileName, R_OK)) {
- LOGE("Couldn't open %s or %s", kSleepFileName, kWakeFileName);
- return NO_INIT;
+ if (access(kOldSleepFileName, R_OK) || access(kOldWakeFileName, R_OK)) {
+ LOGE("Couldn't open %s or %s", kSleepFileName, kWakeFileName);
+ return NO_INIT;
+ }
+ kSleepFileName = kOldSleepFileName;
+ kWakeFileName = kOldWakeFileName;
}
return NO_ERROR;
}
status_t DisplayHardwareBase::DisplayEventThread::initCheck() const
{
- return (access(kSleepFileName, R_OK) == 0 &&
- access(kWakeFileName, R_OK) == 0 &&
+ return (((access(kSleepFileName, R_OK) == 0 &&
+ access(kWakeFileName, R_OK) == 0) ||
+ (access(kOldSleepFileName, R_OK) == 0 &&
+ access(kOldWakeFileName, R_OK) == 0)) &&
access(kFbconSysDir, F_OK) != 0) ? NO_ERROR : NO_INIT;
}
diff --git a/libs/surfaceflinger/GPUHardware/GPUHardware.cpp b/libs/surfaceflinger/GPUHardware/GPUHardware.cpp
index b24a0f2..eb75f99 100644
--- a/libs/surfaceflinger/GPUHardware/GPUHardware.cpp
+++ b/libs/surfaceflinger/GPUHardware/GPUHardware.cpp
@@ -30,6 +30,7 @@
#include <cutils/log.h>
#include <cutils/properties.h>
+#include <utils/IBinder.h>
#include <utils/MemoryDealer.h>
#include <utils/MemoryBase.h>
#include <utils/MemoryHeapPmem.h>
@@ -48,36 +49,113 @@
#include "GPUHardware/GPUHardware.h"
+
/*
- * This file manages the GPU if there is one. The intent is that this code
- * needs to be different for every devce. Currently there is no abstraction,
- * but in the long term, this code needs to be refactored so that API and
- * implementation are separated.
+ * Manage the GPU. This implementation is very specific to the G1.
+ * There are no abstraction here.
+ *
+ * All this code will soon go-away and be replaced by a new architecture
+ * for managing graphics accelerators.
*
- * In this particular implementation, the GPU, its memory and register are
- * managed here. Clients (such as OpenGL ES) request the GPU when then need
- * it and are given a revokable heap containing the registers on memory.
+ * In the meantime, it is conceptually possible to instantiate a
+ * GPUHardwareInterface for another GPU (see GPUFactory at the bottom
+ * of this file); practically... doubtful.
*
*/
namespace android {
+
// ---------------------------------------------------------------------------
+class GPUClientHeap;
+class GPUAreaHeap;
+
+class GPUHardware : public GPUHardwareInterface, public IBinder::DeathRecipient
+{
+public:
+ static const int GPU_RESERVED_SIZE;
+ static const int GPUR_SIZE;
+
+ GPUHardware();
+ virtual ~GPUHardware();
+
+ virtual void revoke(int pid);
+ virtual sp<MemoryDealer> request(int pid);
+ virtual status_t request(int pid,
+ const sp<IGPUCallback>& callback,
+ ISurfaceComposer::gpu_info_t* gpu);
+
+ virtual status_t friendlyRevoke();
+ virtual void unconditionalRevoke();
+
+ virtual pid_t getOwner() const { return mOwner; }
+
+ // used for debugging only...
+ virtual sp<SimpleBestFitAllocator> getAllocator() const;
+
+private:
+
+
+ enum {
+ NO_OWNER = -1,
+ };
+
+ struct GPUArea {
+ sp<GPUAreaHeap> heap;
+ sp<MemoryHeapPmem> clientHeap;
+ sp<IMemory> map();
+ };
+
+ struct Client {
+ pid_t pid;
+ GPUArea smi;
+ GPUArea ebi;
+ GPUArea reg;
+ void createClientHeaps();
+ void revokeAllHeaps();
+ };
+
+ Client& getClientLocked(pid_t pid);
+ status_t requestLocked(int pid);
+ void releaseLocked();
+ void takeBackGPULocked();
+ void registerCallbackLocked(const sp<IGPUCallback>& callback,
+ Client& client);
+
+ virtual void binderDied(const wp<IBinder>& who);
+
+ mutable Mutex mLock;
+ sp<GPUAreaHeap> mSMIHeap;
+ sp<GPUAreaHeap> mEBIHeap;
+ sp<GPUAreaHeap> mREGHeap;
+
+ KeyedVector<pid_t, Client> mClients;
+ DefaultKeyedVector< wp<IBinder>, pid_t > mRegisteredClients;
+
+ pid_t mOwner;
+
+ sp<MemoryDealer> mCurrentAllocator;
+ sp<IGPUCallback> mCallback;
+
+ sp<SimpleBestFitAllocator> mAllocator;
+
+ Condition mCondition;
+};
+
// size reserved for GPU surfaces
// 1200 KB fits exactly:
// - two 320*480 16-bits double-buffered surfaces
// - one 320*480 32-bits double-buffered surface
-// - one 320*240 16-bits double-bufferd, 4x anti-aliased surface
-static const int GPU_RESERVED_SIZE = 1200 * 1024;
-
-static const int GPUR_SIZE = 1 * 1024 * 1024;
+// - one 320*240 16-bits double-buffered, 4x anti-aliased surface
+const int GPUHardware::GPU_RESERVED_SIZE = 1200 * 1024;
+const int GPUHardware::GPUR_SIZE = 1 * 1024 * 1024;
// ---------------------------------------------------------------------------
/*
* GPUHandle is a special IMemory given to the client. It represents their
* handle to the GPU. Once they give it up, they loose GPU access, or if
- * they explicitely revoke their acces through the binder code 1000.
+ * they explicitly revoke their access through the binder code 1000.
* In both cases, this triggers a callback to revoke()
* first, and then actually powers down the chip.
*
@@ -92,42 +170,99 @@ static const int GPUR_SIZE = 1 * 1024 * 1024;
*
*/
-class GPUHandle : public BnMemory
+class GPUClientHeap : public MemoryHeapPmem
{
public:
- GPUHandle(const sp<GPUHardware>& gpu, const sp<IMemoryHeap>& heap)
- : mGPU(gpu), mClientHeap(heap) {
- }
- virtual ~GPUHandle();
- virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
- virtual status_t onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
- void setOwner(int owner) { mOwner = owner; }
+ GPUClientHeap(const wp<GPUHardware>& gpu,
+ const sp<MemoryHeapBase>& heap)
+ : MemoryHeapPmem(heap), mGPU(gpu) { }
+protected:
+ wp<GPUHardware> mGPU;
+};
+
+class GPUAreaHeap : public MemoryHeapBase
+{
+public:
+ GPUAreaHeap(const wp<GPUHardware>& gpu,
+ const char* const vram, size_t size=0, size_t reserved=0)
+ : MemoryHeapBase(vram, size), mGPU(gpu) {
+ if (base() != MAP_FAILED) {
+ if (reserved == 0)
+ reserved = virtualSize();
+ mAllocator = new SimpleBestFitAllocator(reserved);
+ }
+ }
+ virtual sp<MemoryHeapPmem> createClientHeap() {
+ sp<MemoryHeapBase> parentHeap(this);
+ return new GPUClientHeap(mGPU, parentHeap);
+ }
+ virtual const sp<SimpleBestFitAllocator>& getAllocator() const {
+ return mAllocator;
+ }
private:
- void revokeNotification();
+ sp<SimpleBestFitAllocator> mAllocator;
+protected:
wp<GPUHardware> mGPU;
- sp<IMemoryHeap> mClientHeap;
- int mOwner;
};
-GPUHandle::~GPUHandle() {
+class GPURegisterHeap : public GPUAreaHeap
+{
+public:
+ GPURegisterHeap(const sp<GPUHardware>& gpu)
+ : GPUAreaHeap(gpu, "/dev/hw3d", GPUHardware::GPUR_SIZE) { }
+ virtual sp<MemoryHeapPmem> createClientHeap() {
+ sp<MemoryHeapBase> parentHeap(this);
+ return new MemoryHeapRegs(mGPU, parentHeap);
+ }
+private:
+ class MemoryHeapRegs : public GPUClientHeap {
+ public:
+ MemoryHeapRegs(const wp<GPUHardware>& gpu,
+ const sp<MemoryHeapBase>& heap)
+ : GPUClientHeap(gpu, heap) { }
+ sp<MemoryHeapPmem::MemoryPmem> createMemory(size_t offset, size_t size);
+ virtual void revoke();
+ private:
+ class GPUHandle : public MemoryHeapPmem::MemoryPmem {
+ public:
+ GPUHandle(const sp<GPUHardware>& gpu,
+ const sp<MemoryHeapPmem>& heap)
+ : MemoryHeapPmem::MemoryPmem(heap),
+ mGPU(gpu), mOwner(gpu->getOwner()) { }
+ virtual ~GPUHandle();
+ virtual sp<IMemoryHeap> getMemory(
+ ssize_t* offset, size_t* size) const;
+ virtual void revoke() { };
+ virtual status_t onTransact(
+ uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags);
+ private:
+ void revokeNotification();
+ wp<GPUHardware> mGPU;
+ pid_t mOwner;
+ };
+ };
+};
+
+GPURegisterHeap::MemoryHeapRegs::GPUHandle::~GPUHandle() {
//LOGD("GPUHandle %p released, revoking GPU", this);
revokeNotification();
}
-
-void GPUHandle::revokeNotification() {
+void GPURegisterHeap::MemoryHeapRegs::GPUHandle::revokeNotification() {
sp<GPUHardware> hw(mGPU.promote());
if (hw != 0) {
hw->revoke(mOwner);
}
}
-sp<IMemoryHeap> GPUHandle::getMemory(ssize_t* offset, size_t* size) const
+sp<IMemoryHeap> GPURegisterHeap::MemoryHeapRegs::GPUHandle::getMemory(
+ ssize_t* offset, size_t* size) const
{
+ sp<MemoryHeapPmem> heap = getHeap();
if (offset) *offset = 0;
- if (size) *size = mClientHeap !=0 ? mClientHeap->virtualSize() : 0;
- return mClientHeap;
+ if (size) *size = heap !=0 ? heap->virtualSize() : 0;
+ return heap;
}
-status_t GPUHandle::onTransact(
+status_t GPURegisterHeap::MemoryHeapRegs::GPUHandle::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
status_t err = BnMemory::onTransact(code, data, reply, flags);
@@ -150,22 +285,14 @@ status_t GPUHandle::onTransact(
// ---------------------------------------------------------------------------
-class MemoryHeapRegs : public MemoryHeapPmem
-{
-public:
- MemoryHeapRegs(const wp<GPUHardware>& gpu, const sp<MemoryHeapBase>& heap);
- virtual ~MemoryHeapRegs();
- sp<IMemory> mapMemory(size_t offset, size_t size);
- virtual void revoke();
-private:
- wp<GPUHardware> mGPU;
-};
-MemoryHeapRegs::MemoryHeapRegs(const wp<GPUHardware>& gpu, const sp<MemoryHeapBase>& heap)
- : MemoryHeapPmem(heap), mGPU(gpu)
+sp<MemoryHeapPmem::MemoryPmem> GPURegisterHeap::MemoryHeapRegs::createMemory(
+ size_t offset, size_t size)
{
+ sp<GPUHandle> memory;
+ sp<GPUHardware> gpu = mGPU.promote();
+ if (heapID()>0 && gpu!=0) {
#if HAVE_ANDROID_OS
- if (heapID()>0) {
/* this is where the GPU is powered on and the registers are mapped
* in the client */
//LOGD("ioctl(HW3D_GRANT_GPU)");
@@ -174,27 +301,16 @@ MemoryHeapRegs::MemoryHeapRegs(const wp<GPUHardware>& gpu, const sp<MemoryHeapBa
// it can happen if the master heap has been closed already
// in which case the GPU already is revoked (app crash for
// instance).
- //LOGW("HW3D_GRANT_GPU failed (%s), mFD=%d, base=%p",
- // strerror(errno), heapID(), base());
+ LOGW("HW3D_GRANT_GPU failed (%s), mFD=%d, base=%p",
+ strerror(errno), heapID(), base());
}
- }
-#endif
-}
-
-MemoryHeapRegs::~MemoryHeapRegs()
-{
-}
-
-sp<IMemory> MemoryHeapRegs::mapMemory(size_t offset, size_t size)
-{
- sp<GPUHandle> memory;
- sp<GPUHardware> gpu = mGPU.promote();
- if (heapID()>0 && gpu!=0)
memory = new GPUHandle(gpu, this);
+#endif
+ }
return memory;
}
-void MemoryHeapRegs::revoke()
+void GPURegisterHeap::MemoryHeapRegs::revoke()
{
MemoryHeapPmem::revoke();
#if HAVE_ANDROID_OS
@@ -207,25 +323,6 @@ void MemoryHeapRegs::revoke()
#endif
}
-// ---------------------------------------------------------------------------
-
-class GPURegisterHeap : public PMemHeapInterface
-{
-public:
- GPURegisterHeap(const sp<GPUHardware>& gpu)
- : PMemHeapInterface("/dev/hw3d", GPUR_SIZE), mGPU(gpu)
- {
- }
- virtual ~GPURegisterHeap() {
- }
- virtual sp<MemoryHeapPmem> createClientHeap() {
- sp<MemoryHeapBase> parentHeap(this);
- return new MemoryHeapRegs(mGPU, parentHeap);
- }
-private:
- wp<GPUHardware> mGPU;
-};
-
/*****************************************************************************/
GPUHardware::GPUHardware()
@@ -237,85 +334,87 @@ GPUHardware::~GPUHardware()
{
}
-sp<MemoryDealer> GPUHardware::request(int pid)
+status_t GPUHardware::requestLocked(int pid)
{
- sp<MemoryDealer> dealer;
-
- LOGD("pid %d requesting gpu surface (current owner = %d)", pid, mOwner);
-
const int self_pid = getpid();
if (pid == self_pid) {
// can't use GPU from surfaceflinger's process
- return dealer;
+ return PERMISSION_DENIED;
}
- Mutex::Autolock _l(mLock);
-
if (mOwner != pid) {
- // someone already has the gpu.
- takeBackGPULocked();
-
- // releaseLocked() should be a no-op most of the time
- releaseLocked();
-
- requestLocked();
+ if (mREGHeap != 0) {
+ if (mOwner != NO_OWNER) {
+ // someone already has the gpu.
+ takeBackGPULocked();
+ releaseLocked();
+ }
+ } else {
+ // first time, initialize the stuff.
+ if (mSMIHeap == 0)
+ mSMIHeap = new GPUAreaHeap(this, "/dev/pmem_gpu0");
+ if (mEBIHeap == 0)
+ mEBIHeap = new GPUAreaHeap(this,
+ "/dev/pmem_gpu1", 0, GPU_RESERVED_SIZE);
+ mREGHeap = new GPURegisterHeap(this);
+ mAllocator = mEBIHeap->getAllocator();
+ if (mAllocator == NULL) {
+ // something went terribly wrong.
+ mSMIHeap.clear();
+ mEBIHeap.clear();
+ mREGHeap.clear();
+ return INVALID_OPERATION;
+ }
+ }
+ Client& client = getClientLocked(pid);
+ mCurrentAllocator = new MemoryDealer(client.ebi.clientHeap, mAllocator);
+ mOwner = pid;
}
+ return NO_ERROR;
+}
- dealer = mAllocator;
- mOwner = pid;
- if (dealer == 0) {
- mOwner = SURFACE_FAILED;
+sp<MemoryDealer> GPUHardware::request(int pid)
+{
+ sp<MemoryDealer> dealer;
+ Mutex::Autolock _l(mLock);
+ Client* client;
+ LOGD("pid %d requesting gpu surface (current owner = %d)", pid, mOwner);
+ if (requestLocked(pid) == NO_ERROR) {
+ dealer = mCurrentAllocator;
+ LOGD_IF(dealer!=0, "gpu surface granted to pid %d", mOwner);
}
-
- LOGD_IF(dealer!=0, "gpu surface granted to pid %d", mOwner);
return dealer;
}
-status_t GPUHardware::request(const sp<IGPUCallback>& callback,
+status_t GPUHardware::request(int pid, const sp<IGPUCallback>& callback,
ISurfaceComposer::gpu_info_t* gpu)
{
- sp<IMemory> gpuHandle;
- IPCThreadState* ipc = IPCThreadState::self();
- const int pid = ipc->getCallingPid();
- const int self_pid = getpid();
+ if (callback == 0)
+ return BAD_VALUE;
+ sp<IMemory> gpuHandle;
LOGD("pid %d requesting gpu core (owner = %d)", pid, mOwner);
-
- if (pid == self_pid) {
- // can't use GPU from surfaceflinger's process
- return PERMISSION_DENIED;
- }
-
Mutex::Autolock _l(mLock);
- if (mOwner != pid) {
- // someone already has the gpu.
- takeBackGPULocked();
-
- // releaseLocked() should be a no-op most of the time
- releaseLocked();
-
- requestLocked();
- }
-
- if (mHeapR.isValid()) {
+ status_t err = requestLocked(pid);
+ if (err == NO_ERROR) {
+ // it's guaranteed to be there, be construction
+ Client& client = mClients.editValueFor(pid);
+ registerCallbackLocked(callback, client);
gpu->count = 2;
- gpu->regions[0].region = mHeap0.map(true);
- gpu->regions[0].reserved = mHeap0.reserved;
- gpu->regions[1].region = mHeap1.map(true);
- gpu->regions[1].reserved = mHeap1.reserved;
- gpu->regs = mHeapR.map();
+ gpu->regions[0].region = client.smi.map();
+ gpu->regions[1].region = client.ebi.map();
+ gpu->regs = client.reg.map();
+ gpu->regions[0].reserved = 0;
+ gpu->regions[1].reserved = GPU_RESERVED_SIZE;
if (gpu->regs != 0) {
- static_cast< GPUHandle* >(gpu->regs.get())->setOwner(pid);
+ //LOGD("gpu core granted to pid %d, handle base=%p",
+ // mOwner, gpu->regs->pointer());
}
mCallback = callback;
- mOwner = pid;
- //LOGD("gpu core granted to pid %d, handle base=%p",
- // mOwner, gpu->regs->pointer());
} else {
LOGW("couldn't grant gpu core to pid %d", pid);
}
-
- return NO_ERROR;
+ return err;
}
void GPUHardware::revoke(int pid)
@@ -330,16 +429,16 @@ void GPUHardware::revoke(int pid)
// mOwner could be <0 if the same process acquired the GPU
// several times without releasing it first.
mCondition.signal();
- releaseLocked(true);
+ releaseLocked();
}
}
status_t GPUHardware::friendlyRevoke()
{
Mutex::Autolock _l(mLock);
- takeBackGPULocked();
//LOGD("friendlyRevoke owner=%d", mOwner);
- releaseLocked(true);
+ takeBackGPULocked();
+ releaseLocked();
return NO_ERROR;
}
@@ -353,90 +452,37 @@ void GPUHardware::takeBackGPULocked()
}
}
-void GPUHardware::requestLocked()
+void GPUHardware::releaseLocked()
{
- if (mAllocator == 0) {
- GPUPart* part = 0;
- sp<PMemHeap> surfaceHeap;
- if (mHeap1.promote() == false) {
- //LOGD("requestLocked: (1) creating new heap");
- mHeap1.set(new PMemHeap("/dev/pmem_gpu1", 0, GPU_RESERVED_SIZE));
- }
- if (mHeap1.isValid()) {
- //LOGD("requestLocked: (1) heap is valid");
- // NOTE: if GPU1 is available we use it for our surfaces
- // this could be device specific, so we should do something more
- // generic
- surfaceHeap = static_cast< PMemHeap* >( mHeap1.getHeap().get() );
- part = &mHeap1;
- if (mHeap0.promote() == false) {
- //LOGD("requestLocked: (0) creating new heap");
- mHeap0.set(new PMemHeap("/dev/pmem_gpu0"));
- }
- } else {
- //LOGD("requestLocked: (1) heap is not valid");
- // No GPU1, use GPU0 only
- if (mHeap0.promote() == false) {
- //LOGD("requestLocked: (0) creating new heap");
- mHeap0.set(new PMemHeap("/dev/pmem_gpu0", 0, GPU_RESERVED_SIZE));
- }
- if (mHeap0.isValid()) {
- //LOGD("requestLocked: (0) heap is valid");
- surfaceHeap = static_cast< PMemHeap* >( mHeap0.getHeap().get() );
- part = &mHeap0;
- }
- }
-
- if (mHeap0.isValid() || mHeap1.isValid()) {
- if (mHeapR.promote() == false) {
- //LOGD("requestLocked: (R) creating new register heap");
- mHeapR.set(new GPURegisterHeap(this));
- }
- } else {
- // we got nothing...
- mHeap0.clear();
- mHeap1.clear();
- }
-
- if (mHeapR.isValid() == false) {
- //LOGD("requestLocked: (R) register heap not valid!!!");
- // damn, couldn't get the gpu registers!
- mHeap0.clear();
- mHeap1.clear();
- surfaceHeap.clear();
- part = NULL;
- }
-
- if (surfaceHeap != 0 && part && part->getClientHeap()!=0) {
- part->reserved = GPU_RESERVED_SIZE;
- part->surface = true;
- mAllocatorDebug = static_cast<SimpleBestFitAllocator*>(
- surfaceHeap->getAllocator().get());
- mAllocator = new MemoryDealer(
- part->getClientHeap(),
- surfaceHeap->getAllocator());
+ //LOGD("revoking gpu from pid %d", mOwner);
+ if (mOwner != NO_OWNER) {
+ // this may fail because the client might have died, and have
+ // been removed from the list.
+ ssize_t index = mClients.indexOfKey(mOwner);
+ if (index >= 0) {
+ Client& client(mClients.editValueAt(index));
+ client.revokeAllHeaps();
}
+ mOwner = NO_OWNER;
+ mCurrentAllocator.clear();
+ mCallback.clear();
}
}
-void GPUHardware::releaseLocked(bool dispose)
+GPUHardware::Client& GPUHardware::getClientLocked(pid_t pid)
{
- /*
- * if dispose is set, we will force the destruction of the heap,
- * so it is given back to other systems, such as camera.
- * Otherwise, we'll keep a weak pointer to it, this way we might be able
- * to reuse it later if it's still around.
- */
- //LOGD("revoking gpu from pid %d", mOwner);
- mOwner = NO_OWNER;
- mAllocator.clear();
- mCallback.clear();
-
- /* if we're asked for a full revoke, dispose only of the heap
- * we're not using for surface (as we might need it while drawing) */
- mHeap0.release(mHeap0.surface ? false : dispose);
- mHeap1.release(mHeap1.surface ? false : dispose);
- mHeapR.release(false);
+ ssize_t index = mClients.indexOfKey(pid);
+ if (index < 0) {
+ Client client;
+ client.pid = pid;
+ client.smi.heap = mSMIHeap;
+ client.ebi.heap = mEBIHeap;
+ client.reg.heap = mREGHeap;
+ index = mClients.add(pid, client);
+ }
+ Client& client(mClients.editValueAt(index));
+ client.createClientHeaps();
+ return client;
}
// ----------------------------------------------------------------------------
@@ -444,8 +490,7 @@ void GPUHardware::releaseLocked(bool dispose)
sp<SimpleBestFitAllocator> GPUHardware::getAllocator() const {
Mutex::Autolock _l(mLock);
- sp<SimpleBestFitAllocator> allocator = mAllocatorDebug.promote();
- return allocator;
+ return mAllocator;
}
void GPUHardware::unconditionalRevoke()
@@ -456,100 +501,79 @@ void GPUHardware::unconditionalRevoke()
// ---------------------------------------------------------------------------
-
-GPUHardware::GPUPart::GPUPart()
- : surface(false), reserved(0)
-{
-}
-
-GPUHardware::GPUPart::~GPUPart() {
-}
-
-const sp<PMemHeapInterface>& GPUHardware::GPUPart::getHeap() const {
- return mHeap;
-}
-
-const sp<MemoryHeapPmem>& GPUHardware::GPUPart::getClientHeap() const {
- return mClientHeap;
-}
-
-bool GPUHardware::GPUPart::isValid() const {
- return ((mHeap!=0) && (mHeap->base() != MAP_FAILED));
+sp<IMemory> GPUHardware::GPUArea::map() {
+ sp<IMemory> memory;
+ if (clientHeap != 0 && heap != 0) {
+ memory = clientHeap->mapMemory(0, heap->virtualSize());
+ }
+ return memory;
}
-void GPUHardware::GPUPart::clear()
+void GPUHardware::Client::createClientHeaps()
{
- mHeap.clear();
- mHeapWeak.clear();
- mClientHeap.clear();
- surface = false;
+ if (smi.clientHeap == 0)
+ smi.clientHeap = smi.heap->createClientHeap();
+ if (ebi.clientHeap == 0)
+ ebi.clientHeap = ebi.heap->createClientHeap();
+ if (reg.clientHeap == 0)
+ reg.clientHeap = reg.heap->createClientHeap();
}
-void GPUHardware::GPUPart::set(const sp<PMemHeapInterface>& heap)
+void GPUHardware::Client::revokeAllHeaps()
{
- mHeapWeak.clear();
- if (heap!=0 && heap->base() == MAP_FAILED) {
- mHeap.clear();
- mClientHeap.clear();
- } else {
- mHeap = heap;
- mClientHeap = mHeap->createClientHeap();
- }
+ if (smi.clientHeap != 0)
+ smi.clientHeap->revoke();
+ if (ebi.clientHeap != 0)
+ ebi.clientHeap->revoke();
+ if (reg.clientHeap != 0)
+ reg.clientHeap->revoke();
}
-bool GPUHardware::GPUPart::promote()
+void GPUHardware::registerCallbackLocked(const sp<IGPUCallback>& callback,
+ Client& client)
{
- //LOGD("mHeapWeak=%p, mHeap=%p", mHeapWeak.unsafe_get(), mHeap.get());
- if (mHeap == 0) {
- mHeap = mHeapWeak.promote();
+ sp<IBinder> binder = callback->asBinder();
+ if (mRegisteredClients.add(binder, client.pid) >= 0) {
+ binder->linkToDeath(this);
}
- if (mHeap != 0) {
- if (mClientHeap != 0) {
- mClientHeap->revoke();
- }
- mClientHeap = mHeap->createClientHeap();
- } else {
- surface = false;
- }
- return mHeap != 0;
}
-sp<IMemory> GPUHardware::GPUPart::map(bool clear)
+void GPUHardware::binderDied(const wp<IBinder>& who)
{
- sp<IMemory> memory;
- if (mClientHeap != NULL) {
- memory = mClientHeap->mapMemory(0, mHeap->virtualSize());
- if (clear && memory!=0) {
- //StopWatch sw("memset");
- memset(memory->pointer(), 0, memory->size());
+ Mutex::Autolock _l(mLock);
+ pid_t pid = mRegisteredClients.valueFor(who);
+ if (pid != 0) {
+ ssize_t index = mClients.indexOfKey(pid);
+ if (index >= 0) {
+ //LOGD("*** removing client at %d", index);
+ Client& client(mClients.editValueAt(index));
+ client.revokeAllHeaps(); // not really needed in theory
+ mClients.removeItemsAt(index);
+ if (mClients.size() == 0) {
+ //LOGD("*** was last client closing everything");
+ mCallback.clear();
+ mAllocator.clear();
+ mCurrentAllocator.clear();
+ mSMIHeap.clear();
+ mREGHeap.clear();
+
+ // NOTE: we cannot clear the EBI heap because surfaceflinger
+ // itself may be using it, since this is where surfaces
+ // are allocated. if we're in the middle of compositing
+ // a surface (even if its process just died), we cannot
+ // rip the heap under our feet.
+
+ mOwner = NO_OWNER;
+ }
}
}
- return memory;
}
-void GPUHardware::GPUPart::release(bool dispose)
+// ---------------------------------------------------------------------------
+
+sp<GPUHardwareInterface> GPUFactory::getGPU()
{
- if (mClientHeap != 0) {
- mClientHeap->revoke();
- mClientHeap.clear();
- }
- if (dispose) {
- if (mHeapWeak!=0 && mHeap==0) {
- mHeap = mHeapWeak.promote();
- }
- if (mHeap != 0) {
- mHeap->dispose();
- mHeapWeak.clear();
- mHeap.clear();
- } else {
- surface = false;
- }
- } else {
- if (mHeap != 0) {
- mHeapWeak = mHeap;
- mHeap.clear();
- }
- }
+ return new GPUHardware();
}
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/GPUHardware/GPUHardware.h b/libs/surfaceflinger/GPUHardware/GPUHardware.h
index 9a78b99..3354528 100644
--- a/libs/surfaceflinger/GPUHardware/GPUHardware.h
+++ b/libs/surfaceflinger/GPUHardware/GPUHardware.h
@@ -22,92 +22,39 @@
#include <utils/RefBase.h>
#include <utils/threads.h>
+#include <utils/KeyedVector.h>
+
+#include <ui/ISurfaceComposer.h>
namespace android {
// ---------------------------------------------------------------------------
-class GPUHardwareInterface : public RefBase
+class IGPUCallback;
+
+class GPUHardwareInterface : public virtual RefBase
{
public:
virtual void revoke(int pid) = 0;
virtual sp<MemoryDealer> request(int pid) = 0;
- virtual status_t request(const sp<IGPUCallback>& callback,
+ virtual status_t request(int pid, const sp<IGPUCallback>& callback,
ISurfaceComposer::gpu_info_t* gpu) = 0;
virtual status_t friendlyRevoke() = 0;
- virtual void unconditionalRevoke() = 0;
// used for debugging only...
virtual sp<SimpleBestFitAllocator> getAllocator() const = 0;
virtual pid_t getOwner() const = 0;
+ virtual void unconditionalRevoke() = 0;
};
// ---------------------------------------------------------------------------
-class IMemory;
-class MemoryHeapPmem;
-class PMemHeap;
-
-class GPUHardware : public GPUHardwareInterface
-{
+class GPUFactory
+{
public:
- GPUHardware();
- virtual ~GPUHardware();
-
- virtual void revoke(int pid);
- virtual sp<MemoryDealer> request(int pid);
- virtual status_t request(const sp<IGPUCallback>& callback,
- ISurfaceComposer::gpu_info_t* gpu);
-
- virtual status_t friendlyRevoke();
- virtual void unconditionalRevoke();
-
- // used for debugging only...
- virtual sp<SimpleBestFitAllocator> getAllocator() const;
- virtual pid_t getOwner() const { return mOwner; }
-
-private:
- enum {
- NO_OWNER = -1,
- SURFACE_FAILED = -2
- };
-
- void requestLocked();
- void releaseLocked(bool dispose = false);
- void takeBackGPULocked();
-
- class GPUPart
- {
- public:
- bool surface;
- size_t reserved;
- GPUPart();
- ~GPUPart();
- const sp<PMemHeapInterface>& getHeap() const;
- const sp<MemoryHeapPmem>& getClientHeap() const;
- bool isValid() const;
- void clear();
- void set(const sp<PMemHeapInterface>& heap);
- bool promote();
- sp<IMemory> map(bool clear = false);
- void release(bool dispose);
- private:
- sp<PMemHeapInterface> mHeap;
- wp<PMemHeapInterface> mHeapWeak;
- sp<MemoryHeapPmem> mClientHeap;
- };
-
- mutable Mutex mLock;
- GPUPart mHeap0; // SMI
- GPUPart mHeap1; // EBI1
- GPUPart mHeapR;
- sp<MemoryDealer> mAllocator;
- pid_t mOwner;
- sp<IGPUCallback> mCallback;
- wp<SimpleBestFitAllocator> mAllocatorDebug;
-
- Condition mCondition;
+ // the gpu factory
+ static sp<GPUHardwareInterface> getGPU();
};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index 4f6bae1..8ba0851 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -92,26 +92,29 @@ status_t Layer::setBuffers( Client* client,
status_t err = getPixelFormatInfo(format, &info);
if (err) return err;
- // TODO: if eHardware is explicitely requested, we should fail
+ // TODO: if eHardware is explicitly requested, we should fail
// on systems where we can't allocate memory that can be used with
// DMA engines for instance.
+
+ // FIXME: we always ask for hardware for now (this should come from copybit)
+ flags |= ISurfaceComposer::eHardware;
- int memory_type = NATIVE_MEMORY_TYPE_PMEM;
+ const uint32_t memory_flags = flags &
+ (ISurfaceComposer::eGPU |
+ ISurfaceComposer::eHardware |
+ ISurfaceComposer::eSecure);
// pixel-alignment. the final alignment may be bigger because
// we always force a 4-byte aligned bpr.
uint32_t alignment = 1;
- const uint32_t mask = ISurfaceComposer::eGPU | ISurfaceComposer::eSecure;
- if ((flags & mask) == ISurfaceComposer::eGPU) {
- // don't grant GPU memory if GPU is disabled
- char value[PROPERTY_VALUE_MAX];
- property_get("debug.egl.hw", value, "1");
- if (atoi(value) != 0) {
- flags |= ISurfaceComposer::eHardware;
- memory_type = NATIVE_MEMORY_TYPE_GPU;
- // TODO: this value should come from the h/w
- alignment = 8;
+ if (flags & ISurfaceComposer::eGPU) {
+ // FIXME: this value should come from the h/w
+ alignment = 8;
+ // FIXME: this is msm7201A specific, as its GPU only supports
+ // BGRA_8888.
+ if (format == PIXEL_FORMAT_RGBA_8888) {
+ format = PIXEL_FORMAT_BGRA_8888;
}
}
@@ -119,7 +122,7 @@ status_t Layer::setBuffers( Client* client,
mNeedsBlending = (info.h_alpha - info.l_alpha) > 0;
sp<MemoryDealer> allocators[2];
for (int i=0 ; i<2 ; i++) {
- allocators[i] = client->createAllocator(memory_type);
+ allocators[i] = client->createAllocator(memory_flags);
if (allocators[i] == 0)
return NO_MEMORY;
mBuffers[i].init(allocators[i]);
@@ -133,7 +136,7 @@ status_t Layer::setBuffers( Client* client,
mSurface = new Surface(clientIndex(),
allocators[0]->getMemoryHeap(),
allocators[1]->getMemoryHeap(),
- memory_type, mIdentity);
+ mIdentity);
return NO_ERROR;
}
@@ -180,7 +183,7 @@ void Layer::onDraw(const Region& clip) const
front.getBitmapSurface(&src);
copybit_rect_t srect = { 0, 0, t.width, t.height };
- copybit_t* copybit = mFlinger->getBlitEngine();
+ copybit_device_t* copybit = mFlinger->getBlitEngine();
copybit->set_parameter(copybit, COPYBIT_TRANSFORM, getOrientation());
copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
copybit->set_parameter(copybit, COPYBIT_DITHER,
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index 17c9f42..af353e2 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -30,7 +30,7 @@
#include "DisplayHardware/DisplayHardware.h"
-// We don't honor the premultipliad alpha flags, which means that
+// We don't honor the premultiplied alpha flags, which means that
// premultiplied surface may be composed using a non-premultiplied
// equation. We do this because it may be a lot faster on some hardware
// The correct value is HONOR_PREMULTIPLIED_ALPHA = 1
@@ -256,7 +256,7 @@ void LayerBase::validateVisibility(const Transform& planeTransform)
// see if we can/should use 2D h/w with the new configuration
mCanUseCopyBit = false;
- copybit_t* copybit = mFlinger->getBlitEngine();
+ copybit_device_t* copybit = mFlinger->getBlitEngine();
if (copybit) {
const int step = copybit->get(copybit, COPYBIT_ROTATION_STEP_DEG);
const int scaleBits = copybit->get(copybit, COPYBIT_SCALING_FRAC_BITS);
@@ -413,7 +413,7 @@ void LayerBase::drawWithOpenGL(const Region& clip,
// premultiplied alpha.
// If the texture doesn't have an alpha channel we can
- // use REPLACE and switch to non premultiplied-alpha
+ // use REPLACE and switch to non premultiplied alpha
// blending (SRCA/ONE_MINUS_SRCA).
GLenum env, src;
@@ -431,11 +431,11 @@ void LayerBase::drawWithOpenGL(const Region& clip,
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env);
} else {
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glColor4x(0x10000, 0x10000, 0x10000, 0x10000);
if (needsBlending()) {
GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
glEnable(GL_BLEND);
glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
- glColor4x(0x10000, 0x10000, 0x10000, 0x10000);
} else {
glDisable(GL_BLEND);
}
@@ -463,7 +463,7 @@ void LayerBase::drawWithOpenGL(const Region& clip,
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
- // find the smalest power-of-two that will accomodate our surface
+ // find the smallest power-of-two that will accommodate our surface
GLuint tw = 1 << (31 - clz(t.width));
GLuint th = 1 << (31 - clz(t.height));
if (tw < t.width) tw <<= 1;
@@ -556,7 +556,7 @@ void LayerBase::loadTexture(const Region& dirty,
GLuint texture_w = tw;
GLuint texture_h = th;
if (!(flags & DisplayHardware::NPOT_EXTENSION)) {
- // find the smalest power-of-two that will accomodate our surface
+ // find the smallest power-of-two that will accommodate our surface
texture_w = 1 << (31 - clz(t.width));
texture_h = 1 << (31 - clz(t.height));
if (texture_w < t.width) texture_w <<= 1;
@@ -582,6 +582,8 @@ void LayerBase::loadTexture(const Region& dirty,
glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
GL_RGBA, tw, th, 0,
GL_RGBA, GL_UNSIGNED_BYTE, t.data);
+ } else if (t.format == GGL_PIXEL_FORMAT_BGRA_8888) {
+ // TODO: add GL_BGRA extension
} else {
// oops, we don't handle this format, try the regular path
goto regular;
@@ -592,7 +594,7 @@ void LayerBase::loadTexture(const Region& dirty,
regular:
Rect bounds(dirty.bounds());
GLvoid* data = 0;
- if (texture_w!=textureWidth || texture_w!=textureHeight) {
+ if (texture_w!=textureWidth || texture_h!=textureHeight) {
// texture size changed, we need to create a new one
if (!textureWidth || !textureHeight) {
@@ -606,31 +608,36 @@ regular:
bounds.set(Rect(tw, th));
}
}
-
+
if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
glTexImage2D(GL_TEXTURE_2D, 0,
- GL_RGB, tw, th, 0,
+ GL_RGB, texture_w, texture_h, 0,
GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
} else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
glTexImage2D(GL_TEXTURE_2D, 0,
- GL_RGBA, tw, th, 0,
+ GL_RGBA, texture_w, texture_h, 0,
GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
} else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
glTexImage2D(GL_TEXTURE_2D, 0,
- GL_RGBA, tw, th, 0,
+ GL_RGBA, texture_w, texture_h, 0,
GL_RGBA, GL_UNSIGNED_BYTE, data);
} else if ( t.format == GGL_PIXEL_FORMAT_YCbCr_422_SP ||
t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) {
// just show the Y plane of YUV buffers
data = t.data;
glTexImage2D(GL_TEXTURE_2D, 0,
- GL_LUMINANCE, tw, th, 0,
+ GL_LUMINANCE, texture_w, texture_h, 0,
GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
+ } else {
+ // oops, we don't handle this format!
+ LOGE("layer %p, texture=%d, using format %d, which is not "
+ "supported by the GL", this, textureName, t.format);
+ textureName = -1;
}
- textureWidth = tw;
- textureHeight = th;
+ textureWidth = texture_w;
+ textureHeight = texture_h;
}
- if (!data) {
+ if (!data && textureName>=0) {
if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
glTexSubImage2D(GL_TEXTURE_2D, 0,
0, bounds.top, t.width, bounds.height(),
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index 10c1bc1..b3f3771 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -23,6 +23,8 @@
#include <private/ui/LayerState.h>
#include <ui/Region.h>
+#include <ui/Overlay.h>
+
#include <pixelflinger/pixelflinger.h>
#include "Transform.h"
@@ -223,16 +225,14 @@ public:
Surface(SurfaceID id, int identity) {
mParams.token = id;
mParams.identity = identity;
- mParams.type = 0;
}
Surface(SurfaceID id,
const sp<IMemoryHeap>& heap0,
const sp<IMemoryHeap>& heap1,
- int memory_type, int identity)
+ int identity)
{
mParams.token = id;
mParams.identity = identity;
- mParams.type = memory_type;
mParams.heap[0] = heap0;
mParams.heap[1] = heap1;
}
@@ -240,8 +240,8 @@ public:
// TODO: We now have a point here were we can clean-up the
// client's mess.
// This is also where surface id should be recycled.
- //LOGD("Surface %d, heaps={%p, %p}, type=%d destroyed",
- // mId, mHeap[0].get(), mHeap[1].get(), mMemoryType);
+ //LOGD("Surface %d, heaps={%p, %p} destroyed",
+ // mId, mHeap[0].get(), mHeap[1].get());
}
virtual void getSurfaceData(
@@ -254,6 +254,10 @@ public:
{ return INVALID_OPERATION; }
virtual void postBuffer(ssize_t offset) { }
virtual void unregisterBuffers() { };
+ virtual sp<Overlay> createOverlay(
+ uint32_t w, uint32_t h, int32_t format) {
+ return NULL;
+ };
private:
ISurfaceFlingerClient::surface_data_t mParams;
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
index 192ceda..e3ae7fb 100644
--- a/libs/surfaceflinger/LayerBlur.cpp
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -145,11 +145,13 @@ void LayerBlur::onDraw(const Region& clip) const
mRefreshCache = false;
mAutoRefreshPending = false;
- uint16_t* const pixels = (uint16_t*)malloc(w*h*2);
+ // allocate enough memory for 4-bytes (2 pixels) aligned data
+ const int32_t s = (w + 1) & ~1;
+ uint16_t* const pixels = (uint16_t*)malloc(s*h*2);
- // this reads the frame-buffer, so a h/w GL would have to
+ // This reads the frame-buffer, so a h/w GL would have to
// finish() its rendering first. we don't want to do that
- // too often.
+ // too often. Read data is 4-bytes aligned.
glReadPixels(X, Y, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
// blur that texture.
@@ -157,7 +159,7 @@ void LayerBlur::onDraw(const Region& clip) const
bl.version = sizeof(GGLSurface);
bl.width = w;
bl.height = h;
- bl.stride = w;
+ bl.stride = s;
bl.format = GGL_PIXEL_FORMAT_RGB_565;
bl.data = (GGLubyte*)pixels;
blurFilter(&bl, 8, 2);
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index d871fc3..3861e68 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -104,7 +104,7 @@ void LayerBuffer::onDraw(const Region& clip) const
* the requested scale factor, in which case we perform the scaling
* in several passes. */
- copybit_t* copybit = mFlinger->getBlitEngine();
+ copybit_device_t* copybit = mFlinger->getBlitEngine();
const float min = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT);
const float mag = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT);
@@ -123,7 +123,7 @@ void LayerBuffer::onDraw(const Region& clip) const
if (UNLIKELY(mTemporaryDealer == 0)) {
// allocate a memory-dealer for this the first time
mTemporaryDealer = mFlinger->getSurfaceHeapManager()
- ->createHeap(NATIVE_MEMORY_TYPE_PMEM);
+ ->createHeap(ISurfaceComposer::eHardware);
mTempBitmap.init(mTemporaryDealer);
}
@@ -230,7 +230,18 @@ sp<LayerBaseClient::Surface> LayerBuffer::getSurface() const
status_t LayerBuffer::registerBuffers(int w, int h, int hstride, int vstride,
PixelFormat format, const sp<IMemoryHeap>& memoryHeap)
{
- status_t err = (memoryHeap!=0 && memoryHeap->heapID() >= 0) ? NO_ERROR : NO_INIT;
+ if (memoryHeap == NULL) {
+ // this is allowed, but in this case, it is illegal to receive
+ // postBuffer(). The surface just erases the framebuffer with
+ // fully transparent pixels.
+ mHeap.clear();
+ mWidth = w;
+ mHeight = h;
+ mNeedsBlending = false;
+ return NO_ERROR;
+ }
+
+ status_t err = (memoryHeap->heapID() >= 0) ? NO_ERROR : NO_INIT;
if (err != NO_ERROR)
return err;
@@ -281,6 +292,32 @@ void LayerBuffer::unregisterBuffers()
invalidateLocked();
}
+sp<Overlay> LayerBuffer::createOverlay(uint32_t w, uint32_t h, int32_t format)
+{
+ sp<Overlay> result;
+ Mutex::Autolock _l(mLock);
+ if (mHeap != 0 || mBuffer != 0) {
+ // we're a push surface. error.
+ return result;
+ }
+
+ overlay_device_t* overlay_dev = mFlinger->getOverlayEngine();
+ if (overlay_dev == NULL) {
+ // overlays not supported
+ return result;
+ }
+
+ overlay_t* overlay = overlay_dev->createOverlay(overlay_dev, w, h, format);
+ if (overlay == NULL) {
+ // couldn't create the overlay (no memory? no more overlays?)
+ return result;
+ }
+
+ /* TODO: implement the real stuff here */
+
+ return result;
+}
+
sp<LayerBuffer::Buffer> LayerBuffer::getBuffer() const
{
Mutex::Autolock _l(mLock);
@@ -330,6 +367,15 @@ void LayerBuffer::SurfaceBuffer::unregisterBuffers()
owner->unregisterBuffers();
}
+sp<Overlay> LayerBuffer::SurfaceBuffer::createOverlay(
+ uint32_t w, uint32_t h, int32_t format) {
+ sp<Overlay> result;
+ LayerBuffer* owner(getOwner());
+ if (owner)
+ result = owner->createOverlay(w, h, format);
+ return result;
+}
+
void LayerBuffer::SurfaceBuffer::disown()
{
Mutex::Autolock _l(mLock);
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index ef473dd..3e616f2 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -33,6 +33,7 @@ namespace android {
class MemoryDealer;
class Region;
+class Overlay;
class LayerBuffer : public LayerBaseClient
{
@@ -56,6 +57,7 @@ public:
PixelFormat format, const sp<IMemoryHeap>& heap);
void postBuffer(ssize_t offset);
void unregisterBuffers();
+ sp<Overlay> createOverlay(uint32_t w, uint32_t h, int32_t format);
void invalidate();
void invalidateLocked();
@@ -107,7 +109,9 @@ private:
PixelFormat format, const sp<IMemoryHeap>& heap);
virtual void postBuffer(ssize_t offset);
virtual void unregisterBuffers();
- void disown();
+ virtual sp<Overlay> createOverlay(
+ uint32_t w, uint32_t h, int32_t format);
+ void disown();
private:
LayerBuffer* getOwner() const {
Mutex::Autolock _l(mLock);
diff --git a/libs/surfaceflinger/LayerDim.cpp b/libs/surfaceflinger/LayerDim.cpp
index fc23d53..0c347cc 100644
--- a/libs/surfaceflinger/LayerDim.cpp
+++ b/libs/surfaceflinger/LayerDim.cpp
@@ -48,7 +48,7 @@ void LayerDim::initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h)
{
// must only be called once.
mDimmerDealer = flinger->getSurfaceHeapManager()
- ->createHeap(NATIVE_MEMORY_TYPE_PMEM);
+ ->createHeap(ISurfaceComposer::eHardware);
if (mDimmerDealer != 0) {
mDimmerBitmap.init(mDimmerDealer);
mDimmerBitmap.setBits(w, h, 1, PIXEL_FORMAT_RGB_565);
@@ -81,7 +81,7 @@ void LayerDim::onDraw(const Region& clip) const
mDimmerBitmap.getBitmapSurface(&src);
const copybit_rect_t& srect(drect);
- copybit_t* copybit = mFlinger->getBlitEngine();
+ copybit_device_t* copybit = mFlinger->getBlitEngine();
copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 45496b2..e8de21a 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -38,7 +38,6 @@
#include <utils/String16.h>
#include <utils/StopWatch.h>
-#include <ui/BlitHardware.h>
#include <ui/PixelFormat.h>
#include <ui/DisplayInfo.h>
#include <ui/EGLDisplaySurface.h>
@@ -202,23 +201,6 @@ void SurfaceFlinger::init()
{
LOGI("SurfaceFlinger is starting");
- // create the shared control-block
- mServerHeap = new MemoryDealer(4096, MemoryDealer::READ_ONLY);
- LOGE_IF(mServerHeap==0, "can't create shared memory dealer");
-
- mServerCblkMemory = mServerHeap->allocate(4096);
- LOGE_IF(mServerCblkMemory==0, "can't create shared control block");
-
- mServerCblk = static_cast<surface_flinger_cblk_t *>(mServerCblkMemory->pointer());
- LOGE_IF(mServerCblk==0, "can't get to shared control block's address");
- new(mServerCblk) surface_flinger_cblk_t;
-
- // create the surface Heap manager, which manages the heaps
- // (be it in RAM or VRAM) where surfaces are allocated
- // We give 8 MB per client.
- mSurfaceHeapManager = new SurfaceHeapManager(8 << 20);
- mGPU = new GPUHardware();
-
// debugging stuff...
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.showupdates", value, "0");
@@ -244,11 +226,16 @@ SurfaceFlinger::~SurfaceFlinger()
glDeleteTextures(1, &mWormholeTexName);
}
-copybit_t* SurfaceFlinger::getBlitEngine() const
+copybit_device_t* SurfaceFlinger::getBlitEngine() const
{
return graphicPlane(0).displayHardware().getBlitEngine();
}
+overlay_device_t* SurfaceFlinger::getOverlayEngine() const
+{
+ return graphicPlane(0).displayHardware().getOverlayEngine();
+}
+
sp<IMemory> SurfaceFlinger::getCblk() const
{
return mServerCblkMemory;
@@ -257,7 +244,9 @@ sp<IMemory> SurfaceFlinger::getCblk() const
status_t SurfaceFlinger::requestGPU(const sp<IGPUCallback>& callback,
gpu_info_t* gpu)
{
- status_t err = mGPU->request(callback, gpu);
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ status_t err = mGPU->request(pid, callback, gpu);
return err;
}
@@ -360,7 +349,26 @@ status_t SurfaceFlinger::readyToRun()
LOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
- //
+ // create the shared control-block
+ mServerHeap = new MemoryDealer(4096, MemoryDealer::READ_ONLY);
+ LOGE_IF(mServerHeap==0, "can't create shared memory dealer");
+
+ mServerCblkMemory = mServerHeap->allocate(4096);
+ LOGE_IF(mServerCblkMemory==0, "can't create shared control block");
+
+ mServerCblk = static_cast<surface_flinger_cblk_t *>(mServerCblkMemory->pointer());
+ LOGE_IF(mServerCblk==0, "can't get to shared control block's address");
+ new(mServerCblk) surface_flinger_cblk_t;
+
+ // get a reference to the GPU if we have one
+ mGPU = GPUFactory::getGPU();
+
+ // create the surface Heap manager, which manages the heaps
+ // (be it in RAM or VRAM) where surfaces are allocated
+ // We give 8 MB per client.
+ mSurfaceHeapManager = new SurfaceHeapManager(this, 8 << 20);
+
+
GLES_localSurfaceManager = static_cast<ISurfaceComposer*>(this);
// we only support one display currently
@@ -395,7 +403,7 @@ status_t SurfaceFlinger::readyToRun()
dcblk->xdpi = hw.getDpiX();
dcblk->ydpi = hw.getDpiY();
dcblk->fps = hw.getRefreshRate();
- dcblk->density = 1.0f; // XXX: do someting more real here...
+ dcblk->density = hw.getDensity();
asm volatile ("":::"memory");
// Initialize OpenGL|ES
@@ -407,6 +415,7 @@ status_t SurfaceFlinger::readyToRun()
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+ glPixelStorei(GL_PACK_ALIGNMENT, 4);
glEnableClientState(GL_VERTEX_ARRAY);
glEnable(GL_SCISSOR_TEST);
glShadeModel(GL_FLAT);
@@ -1679,7 +1688,7 @@ status_t SurfaceFlinger::onTransact(
Client::Client(ClientID clientID, const sp<SurfaceFlinger>& flinger)
: ctrlblk(0), cid(clientID), mPid(0), mBitmap(0), mFlinger(flinger)
{
- mSharedHeapAllocator = getSurfaceHeapManager()->createHeap(NATIVE_MEMORY_TYPE_HEAP);
+ mSharedHeapAllocator = getSurfaceHeapManager()->createHeap();
const int pgsize = getpagesize();
const int cblksize=((sizeof(per_client_cblk_t)+(pgsize-1))&~(pgsize-1));
mCblkHeap = new MemoryDealer(cblksize);
@@ -1703,10 +1712,6 @@ const sp<SurfaceHeapManager>& Client::getSurfaceHeapManager() const {
return mFlinger->getSurfaceHeapManager();
}
-const sp<GPUHardwareInterface>& Client::getGPU() const {
- return mFlinger->getGPU();
-}
-
int32_t Client::generateId(int pid)
{
const uint32_t i = clz( ~mBitmap );
@@ -1734,25 +1739,11 @@ void Client::free(int32_t id)
}
}
-sp<MemoryDealer> Client::createAllocator(int memory_type)
+sp<MemoryDealer> Client::createAllocator(uint32_t flags)
{
sp<MemoryDealer> allocator;
- if (memory_type == NATIVE_MEMORY_TYPE_GPU) {
- allocator = getGPU()->request(getClientPid());
- if (allocator == 0)
- memory_type = NATIVE_MEMORY_TYPE_PMEM;
- }
- if (memory_type == NATIVE_MEMORY_TYPE_PMEM) {
- allocator = mPMemAllocator;
- if (allocator == 0) {
- allocator = getSurfaceHeapManager()->createHeap(
- NATIVE_MEMORY_TYPE_PMEM);
- mPMemAllocator = allocator;
- }
- }
- if (allocator == 0)
- allocator = mSharedHeapAllocator;
-
+ allocator = getSurfaceHeapManager()->createHeap(
+ flags, getClientPid(), mSharedHeapAllocator);
return allocator;
}
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index 1581474..92021d0 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -41,7 +41,8 @@
#include "BootAnimation.h"
#include "Barrier.h"
-struct copybit_t;
+struct copybit_device_t;
+struct overlay_device_t;
namespace android {
@@ -74,7 +75,7 @@ public:
int32_t generateId(int pid);
void free(int32_t id);
status_t bindLayer(LayerBaseClient* layer, int32_t id);
- sp<MemoryDealer> createAllocator(int memory_type);
+ sp<MemoryDealer> createAllocator(uint32_t memory_type);
inline bool isValid(int32_t i) const;
inline const uint8_t* inUseArray() const;
@@ -92,7 +93,6 @@ public:
private:
int getClientPid() const { return mPid; }
- const sp<GPUHardwareInterface>& getGPU() const;
int mPid;
uint32_t mBitmap;
@@ -179,7 +179,8 @@ public:
return mGPU;
}
- copybit_t* getBlitEngine() const;
+ copybit_device_t* getBlitEngine() const;
+ overlay_device_t* getOverlayEngine() const;
private:
friend class BClient;
diff --git a/libs/surfaceflinger/VRamHeap.cpp b/libs/surfaceflinger/VRamHeap.cpp
index 3852d51..77bc576 100644
--- a/libs/surfaceflinger/VRamHeap.cpp
+++ b/libs/surfaceflinger/VRamHeap.cpp
@@ -37,6 +37,8 @@
#include <GLES/eglnatives.h>
+#include "GPUHardware/GPUHardware.h"
+#include "SurfaceFlinger.h"
#include "VRamHeap.h"
#if HAVE_ANDROID_OS
@@ -59,8 +61,9 @@ int SurfaceHeapManager::global_pmem_heap = 0;
// ---------------------------------------------------------------------------
-SurfaceHeapManager::SurfaceHeapManager(size_t clientHeapSize)
- : mClientHeapSize(clientHeapSize)
+SurfaceHeapManager::SurfaceHeapManager(const sp<SurfaceFlinger>& flinger,
+ size_t clientHeapSize)
+ : mFlinger(flinger), mClientHeapSize(clientHeapSize)
{
SurfaceHeapManager::global_pmem_heap = 1;
}
@@ -81,25 +84,53 @@ void SurfaceHeapManager::onFirstRef()
}
}
-sp<MemoryDealer> SurfaceHeapManager::createHeap(int type)
+sp<MemoryDealer> SurfaceHeapManager::createHeap(
+ uint32_t flags,
+ pid_t client_pid,
+ const sp<MemoryDealer>& defaultAllocator)
{
- if (!global_pmem_heap && type==NATIVE_MEMORY_TYPE_PMEM)
- type = NATIVE_MEMORY_TYPE_HEAP;
-
- const sp<PMemHeap>& heap(mPMemHeap);
sp<MemoryDealer> dealer;
- switch (type) {
- case NATIVE_MEMORY_TYPE_HEAP:
- dealer = new MemoryDealer(mClientHeapSize, 0, "SFNativeHeap");
- break;
- case NATIVE_MEMORY_TYPE_PMEM:
- if (heap != 0) {
- dealer = new MemoryDealer(
- heap->createClientHeap(),
- heap->getAllocator());
+ if (flags & ISurfaceComposer::eGPU) {
+ // don't grant GPU memory if GPU is disabled
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.egl.hw", value, "1");
+ if (atoi(value) == 0) {
+ flags &= ~ISurfaceComposer::eGPU;
+ }
+ }
+
+ if (flags & ISurfaceComposer::eGPU) {
+ // FIXME: this is msm7201A specific, where gpu surfaces may not be secure
+ if (!(flags & ISurfaceComposer::eSecure)) {
+ // if GPU doesn't work, we try eHardware
+ flags |= ISurfaceComposer::eHardware;
+ // asked for GPU memory, try that first
+ dealer = mFlinger->getGPU()->request(client_pid);
+ }
+ }
+
+ if (dealer == NULL) {
+ if (defaultAllocator != NULL)
+ // if a default allocator is given, use that
+ dealer = defaultAllocator;
+ }
+
+ if (dealer == NULL) {
+ // always try h/w accelerated memory first
+ if (global_pmem_heap) {
+ const sp<PMemHeap>& heap(mPMemHeap);
+ if (dealer == NULL && heap != NULL) {
+ dealer = new MemoryDealer(
+ heap->createClientHeap(),
+ heap->getAllocator());
+ }
}
- break;
+ }
+
+ if (dealer == NULL) {
+ // return the ashmem allocator (software rendering)
+ dealer = new MemoryDealer(mClientHeapSize, 0, "SFNativeHeap");
}
return dealer;
}
@@ -122,22 +153,8 @@ sp<SimpleBestFitAllocator> SurfaceHeapManager::getAllocator(int type) const
// ---------------------------------------------------------------------------
-PMemHeapInterface::PMemHeapInterface(int fd, size_t size)
- : MemoryHeapBase(fd, size) {
-}
-PMemHeapInterface::PMemHeapInterface(const char* device, size_t size)
- : MemoryHeapBase(device, size) {
-}
-PMemHeapInterface::PMemHeapInterface(size_t size, uint32_t flags, char const * name)
- : MemoryHeapBase(size, flags, name) {
-}
-PMemHeapInterface::~PMemHeapInterface() {
-}
-
-// ---------------------------------------------------------------------------
-
PMemHeap::PMemHeap(const char* const device, size_t size, size_t reserved)
- : PMemHeapInterface(device, size)
+ : MemoryHeapBase(device, size)
{
//LOGD("%s, %p, mFD=%d", __PRETTY_FUNCTION__, this, heapID());
if (base() != MAP_FAILED) {
diff --git a/libs/surfaceflinger/VRamHeap.h b/libs/surfaceflinger/VRamHeap.h
index 03e0336..9140167 100644
--- a/libs/surfaceflinger/VRamHeap.h
+++ b/libs/surfaceflinger/VRamHeap.h
@@ -27,16 +27,19 @@ namespace android {
class PMemHeap;
class MemoryHeapPmem;
+class SurfaceFlinger;
// ---------------------------------------------------------------------------
class SurfaceHeapManager : public RefBase
{
public:
- SurfaceHeapManager(size_t clientHeapSize);
+ SurfaceHeapManager(const sp<SurfaceFlinger>& flinger, size_t clientHeapSize);
virtual ~SurfaceHeapManager();
virtual void onFirstRef();
- sp<MemoryDealer> createHeap(int type);
+ /* use ISurfaceComposer flags eGPU|eHArdware|eSecure */
+ sp<MemoryDealer> createHeap(uint32_t flags=0, pid_t client_pid = 0,
+ const sp<MemoryDealer>& defaultAllocator = 0);
// used for debugging only...
sp<SimpleBestFitAllocator> getAllocator(int type) const;
@@ -44,6 +47,7 @@ public:
private:
sp<PMemHeap> getHeap(int type) const;
+ sp<SurfaceFlinger> mFlinger;
mutable Mutex mLock;
size_t mClientHeapSize;
sp<PMemHeap> mPMemHeap;
@@ -52,19 +56,7 @@ private:
// ---------------------------------------------------------------------------
-class PMemHeapInterface : public MemoryHeapBase
-{
-public:
- PMemHeapInterface(int fd, size_t size);
- PMemHeapInterface(const char* device, size_t size = 0);
- PMemHeapInterface(size_t size, uint32_t flags = 0, char const * name = NULL);
- virtual ~PMemHeapInterface();
- virtual sp<MemoryHeapPmem> createClientHeap() = 0;
-};
-
-// ---------------------------------------------------------------------------
-
-class PMemHeap : public PMemHeapInterface
+class PMemHeap : public MemoryHeapBase
{
public:
PMemHeap(const char* const vram,
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 71579c5..7b51300 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -2,7 +2,6 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- BlitHardware.cpp \
Camera.cpp \
CameraParameters.cpp \
EGLDisplaySurface.cpp \
@@ -14,10 +13,12 @@ LOCAL_SRC_FILES:= \
ICamera.cpp \
ICameraClient.cpp \
ICameraService.cpp \
+ IOverlay.cpp \
ISurfaceComposer.cpp \
ISurface.cpp \
ISurfaceFlingerClient.cpp \
LayerState.cpp \
+ Overlay.cpp \
PixelFormat.cpp \
Point.cpp \
Rect.cpp \
diff --git a/libs/ui/BlitHardware.cpp b/libs/ui/BlitHardware.cpp
deleted file mode 100644
index 90838b4..0000000
--- a/libs/ui/BlitHardware.cpp
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "SurfaceFlinger"
-
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-
-#include <cutils/log.h>
-
-#include <utils/Errors.h>
-
-#if HAVE_ANDROID_OS
-#include <linux/fb.h>
-#include <linux/msm_mdp.h>
-#endif
-
-#include <ui/BlitHardware.h>
-
-/******************************************************************************/
-
-namespace android {
-class CopybitMSM7K : public copybit_t {
-public:
- CopybitMSM7K();
- ~CopybitMSM7K();
-
- status_t getStatus() const {
- if (mFD<0) return mFD;
- return NO_ERROR;
- }
-
- status_t setParameter(int name, int value);
-
- status_t get(int name);
-
- status_t blit(
- const copybit_image_t& dst,
- const copybit_image_t& src,
- copybit_region_t const* region);
-
- status_t stretch(
- const copybit_image_t& dst,
- const copybit_image_t& src,
- const copybit_rect_t& dst_rect,
- const copybit_rect_t& src_rect,
- copybit_region_t const* region);
-
-#if HAVE_ANDROID_OS
-private:
- static int copybit_set_parameter(copybit_t* handle, int name, int value);
- static int copybit_blit( copybit_t* handle,
- copybit_image_t const* dst, copybit_image_t const* src,
- copybit_region_t const* region);
- static int copybit_stretch(copybit_t* handle,
- copybit_image_t const* dst, copybit_image_t const* src,
- copybit_rect_t const* dst_rect, copybit_rect_t const* src_rect,
- copybit_region_t const* region);
- static int copybit_get(copybit_t* handle, int name);
-
- int getFormat(int format);
- void setImage(mdp_img* img, const copybit_image_t& rhs);
- void setRects(mdp_blit_req* req, const copybit_rect_t& dst,
- const copybit_rect_t& src, const copybit_rect_t& scissor);
- void setInfos(mdp_blit_req* req);
- static void intersect(copybit_rect_t* out,
- const copybit_rect_t& lhs, const copybit_rect_t& rhs);
- status_t msm_copybit(void const* list);
-#endif
- int mFD;
- uint8_t mAlpha;
- uint8_t mFlags;
-};
-}; // namespace android
-
-using namespace android;
-
-/******************************************************************************/
-
-struct copybit_t* copybit_init()
-{
- CopybitMSM7K* engine = new CopybitMSM7K();
- if (engine->getStatus() != NO_ERROR) {
- delete engine;
- engine = 0;
- }
- return (struct copybit_t*)engine;
-
-}
-
-int copybit_term(copybit_t* handle)
-{
- delete static_cast<CopybitMSM7K*>(handle);
- return NO_ERROR;
-}
-
-namespace android {
-/******************************************************************************/
-
-static inline
-int min(int a, int b) {
- return (a<b) ? a : b;
-}
-
-static inline
-int max(int a, int b) {
- return (a>b) ? a : b;
-}
-
-static inline
-void MULDIV(uint32_t& a, uint32_t& b, int mul, int div)
-{
- if (mul != div) {
- a = (mul * a) / div;
- b = (mul * b) / div;
- }
-}
-
-//-----------------------------------------------------------------------------
-
-#if HAVE_ANDROID_OS
-
-int CopybitMSM7K::copybit_set_parameter(copybit_t* handle, int name, int value)
-{
- return static_cast<CopybitMSM7K*>(handle)->setParameter(name, value);
-}
-
-int CopybitMSM7K::copybit_get(copybit_t* handle, int name)
-{
- return static_cast<CopybitMSM7K*>(handle)->get(name);
-}
-
-int CopybitMSM7K::copybit_blit(
- copybit_t* handle,
- copybit_image_t const* dst,
- copybit_image_t const* src,
- struct copybit_region_t const* region)
-{
- return static_cast<CopybitMSM7K*>(handle)->blit(*dst, *src, region);
-}
-
-int CopybitMSM7K::copybit_stretch(
- copybit_t* handle,
- copybit_image_t const* dst,
- copybit_image_t const* src,
- copybit_rect_t const* dst_rect,
- copybit_rect_t const* src_rect,
- struct copybit_region_t const* region)
-{
- return static_cast<CopybitMSM7K*>(handle)->stretch(
- *dst, *src, *dst_rect, *src_rect, region);
-}
-
-//-----------------------------------------------------------------------------
-
-CopybitMSM7K::CopybitMSM7K()
- : mFD(-1), mAlpha(MDP_ALPHA_NOP), mFlags(0)
-{
- int fd = open("/dev/graphics/fb0", O_RDWR, 0);
- if (fd > 0) {
- struct fb_fix_screeninfo finfo;
- if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == 0) {
- if (!strcmp(finfo.id, "msmfb")) {
- mFD = fd;
- copybit_t::set_parameter = copybit_set_parameter;
- copybit_t::get = copybit_get;
- copybit_t::blit = copybit_blit;
- copybit_t::stretch = copybit_stretch;
- }
- }
- }
- if (fd<0 || mFD<0) {
- if (fd>0) { close(fd); }
- mFD = -errno;
- }
-}
-
-CopybitMSM7K::~CopybitMSM7K()
-{
- if (mFD > 0){
- close(mFD);
- }
-}
-
-status_t CopybitMSM7K::setParameter(int name, int value)
-{
- switch(name) {
- case COPYBIT_ROTATION_DEG:
- switch (value) {
- case 0:
- mFlags &= ~0x7;
- break;
- case 90:
- mFlags &= ~0x7;
- mFlags |= MDP_ROT_90;
- break;
- case 180:
- mFlags &= ~0x7;
- mFlags |= MDP_ROT_180;
- break;
- case 270:
- mFlags &= ~0x7;
- mFlags |= MDP_ROT_270;
- break;
- default:
- return BAD_VALUE;
- }
- break;
- case COPYBIT_PLANE_ALPHA:
- if (value < 0) value = 0;
- if (value >= 256) value = 255;
- mAlpha = value;
- break;
- case COPYBIT_DITHER:
- if (value == COPYBIT_ENABLE) {
- mFlags |= MDP_DITHER;
- } else if (value == COPYBIT_DISABLE) {
- mFlags &= ~MDP_DITHER;
- }
- break;
- case COPYBIT_TRANSFORM:
- mFlags &= ~0x7;
- mFlags |= value & 0x7;
- break;
- default:
- return BAD_VALUE;
- }
- return NO_ERROR;
-}
-
-status_t CopybitMSM7K::get(int name)
-{
- switch(name) {
- case COPYBIT_MINIFICATION_LIMIT:
- return 4;
- case COPYBIT_MAGNIFICATION_LIMIT:
- return 4;
- case COPYBIT_SCALING_FRAC_BITS:
- return 32;
- case COPYBIT_ROTATION_STEP_DEG:
- return 90;
- }
- return BAD_VALUE;
-}
-
-status_t CopybitMSM7K::blit(
- const copybit_image_t& dst,
- const copybit_image_t& src,
- copybit_region_t const* region)
-{
-
- copybit_rect_t dr = { 0, 0, dst.w, dst.h };
- copybit_rect_t sr = { 0, 0, src.w, src.h };
- return CopybitMSM7K::stretch(dst, src, dr, sr, region);
-}
-
-status_t CopybitMSM7K::stretch(
- const copybit_image_t& dst,
- const copybit_image_t& src,
- const copybit_rect_t& dst_rect,
- const copybit_rect_t& src_rect,
- copybit_region_t const* region)
-{
- struct {
- uint32_t count;
- struct mdp_blit_req req[12];
- } list;
-
- if (mAlpha<255) {
- switch (src.format) {
- // we dont' support plane alpha with RGBA formats
- case COPYBIT_RGBA_8888:
- case COPYBIT_RGBA_5551:
- case COPYBIT_RGBA_4444:
- return INVALID_OPERATION;
- }
- }
-
- const uint32_t maxCount = sizeof(list.req)/sizeof(list.req[0]);
- const copybit_rect_t bounds = { 0, 0, dst.w, dst.h };
- copybit_rect_t clip;
- list.count = 0;
- int err = 0;
- while (!err && region->next(region, &clip)) {
- intersect(&clip, bounds, clip);
- setInfos(&list.req[list.count]);
- setImage(&list.req[list.count].dst, dst);
- setImage(&list.req[list.count].src, src);
- setRects(&list.req[list.count], dst_rect, src_rect, clip);
- if (++list.count == maxCount) {
- err = msm_copybit(&list);
- list.count = 0;
- }
- }
- if (!err && list.count) {
- err = msm_copybit(&list);
- }
- return err;
-}
-
-status_t CopybitMSM7K::msm_copybit(void const* list)
-{
- int err = ioctl(mFD, MSMFB_BLIT, static_cast<mdp_blit_req_list const*>(list));
- LOGE_IF(err<0, "copyBits failed (%s)", strerror(errno));
- if (err == 0)
- return NO_ERROR;
- return -errno;
-}
-
-int CopybitMSM7K::getFormat(int format)
-{
- switch (format) {
- case COPYBIT_RGBA_8888: return MDP_RGBA_8888;
- case COPYBIT_RGB_565: return MDP_RGB_565;
- case COPYBIT_YCbCr_422_SP: return MDP_Y_CBCR_H2V1;
- case COPYBIT_YCbCr_420_SP: return MDP_Y_CBCR_H2V2;
- }
- return -1;
-}
-
-void CopybitMSM7K::setInfos(mdp_blit_req* req)
-{
- req->alpha = mAlpha;
- req->transp_mask = MDP_TRANSP_NOP;
- req->flags = mFlags;
-}
-
-void CopybitMSM7K::setImage(mdp_img* img, const copybit_image_t& rhs)
-{
- img->width = rhs.w;
- img->height = rhs.h;
- img->format = getFormat(rhs.format);
- img->offset = rhs.offset;
- img->memory_id = rhs.fd;
-}
-
-void CopybitMSM7K::setRects(mdp_blit_req* e,
- const copybit_rect_t& dst, const copybit_rect_t& src,
- const copybit_rect_t& scissor)
-{
- copybit_rect_t clip;
- intersect(&clip, scissor, dst);
-
- e->dst_rect.x = clip.l;
- e->dst_rect.y = clip.t;
- e->dst_rect.w = clip.r - clip.l;
- e->dst_rect.h = clip.b - clip.t;
-
- uint32_t W, H;
- if (mFlags & COPYBIT_TRANSFORM_ROT_90) {
- e->src_rect.x = (clip.t - dst.t) + src.t;
- e->src_rect.y = (dst.r - clip.r) + src.l;
- e->src_rect.w = (clip.b - clip.t);
- e->src_rect.h = (clip.r - clip.l);
- W = dst.b - dst.t;
- H = dst.r - dst.l;
- } else {
- e->src_rect.x = (clip.l - dst.l) + src.l;
- e->src_rect.y = (clip.t - dst.t) + src.t;
- e->src_rect.w = (clip.r - clip.l);
- e->src_rect.h = (clip.b - clip.t);
- W = dst.r - dst.l;
- H = dst.b - dst.t;
- }
- MULDIV(e->src_rect.x, e->src_rect.w, src.r - src.l, W);
- MULDIV(e->src_rect.y, e->src_rect.h, src.b - src.t, H);
- if (mFlags & COPYBIT_TRANSFORM_FLIP_V) {
- e->src_rect.y = e->src.height - (e->src_rect.y + e->src_rect.h);
- }
- if (mFlags & COPYBIT_TRANSFORM_FLIP_H) {
- e->src_rect.x = e->src.width - (e->src_rect.x + e->src_rect.w);
- }
-}
-
-void CopybitMSM7K::intersect(copybit_rect_t* out,
- const copybit_rect_t& lhs, const copybit_rect_t& rhs)
-{
- out->l = max(lhs.l, rhs.l);
- out->t = max(lhs.t, rhs.t);
- out->r = min(lhs.r, rhs.r);
- out->b = min(lhs.b, rhs.b);
-}
-
-/******************************************************************************/
-#else // HAVE_ANDROID_OS
-
-CopybitMSM7K::CopybitMSM7K()
- : mFD(-1)
-{
-}
-
-CopybitMSM7K::~CopybitMSM7K()
-{
-}
-
-status_t CopybitMSM7K::setParameter(int name, int value)
-{
- return NO_INIT;
-}
-
-status_t CopybitMSM7K::get(int name)
-{
- return BAD_VALUE;
-}
-
-status_t CopybitMSM7K::blit(
- const copybit_image_t& dst,
- const copybit_image_t& src,
- copybit_region_t const* region)
-{
- return NO_INIT;
-}
-
-status_t CopybitMSM7K::stretch(
- const copybit_image_t& dst,
- const copybit_image_t& src,
- const copybit_rect_t& dst_rect,
- const copybit_rect_t& src_rect,
- copybit_region_t const* region)
-{
- return NO_INIT;
-}
-
-#endif // HAVE_ANDROID_OS
-
-/******************************************************************************/
-}; // namespace android
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index 1528e6e..9527009 100644
--- a/libs/ui/Camera.cpp
+++ b/libs/ui/Camera.cpp
@@ -1,28 +1,28 @@
/*
**
-** Copyright 2008, The Android Open Source Project
+** Copyright (C) 2008, The Android Open Source Project
+** Copyright (C) 2008 HTC Inc.
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
+//#define LOG_NDEBUG 0
#define LOG_TAG "Camera"
#include <utils/Log.h>
-
#include <utils/IServiceManager.h>
#include <utils/threads.h>
#include <utils/IMemory.h>
#include <ui/Surface.h>
-
#include <ui/Camera.h>
#include <ui/ICameraService.h>
@@ -60,20 +60,36 @@ const sp<ICameraService>& Camera::getCameraService()
// ---------------------------------------------------------------------------
Camera::Camera()
- : mStatus(UNKNOWN_ERROR),
- mShutterCallback(0),
- mShutterCallbackCookie(0),
- mRawCallback(0),
- mRawCallbackCookie(0),
- mJpegCallback(0),
- mJpegCallbackCookie(0),
- mFrameCallback(0),
- mFrameCallbackCookie(0),
- mErrorCallback(0),
- mErrorCallbackCookie(0),
- mAutoFocusCallback(0),
- mAutoFocusCallbackCookie(0)
{
+ init();
+}
+
+Camera::Camera(const sp<ICamera>& camera)
+{
+ init();
+ // connect this client to existing camera remote
+ if (camera->connect(this) == NO_ERROR) {
+ mStatus = NO_ERROR;
+ mCamera = camera;
+ camera->asBinder()->linkToDeath(this);
+ }
+}
+
+void Camera::init()
+{
+ mStatus = UNKNOWN_ERROR;
+ mShutterCallback = 0;
+ mShutterCallbackCookie = 0;
+ mRawCallback = 0;
+ mRawCallbackCookie = 0;
+ mJpegCallback = 0;
+ mJpegCallbackCookie = 0;
+ mFrameCallback = 0;
+ mFrameCallbackCookie = 0;
+ mErrorCallback = 0;
+ mErrorCallbackCookie = 0;
+ mAutoFocusCallback = 0;
+ mAutoFocusCallbackCookie = 0;
}
Camera::~Camera()
@@ -83,6 +99,7 @@ Camera::~Camera()
sp<Camera> Camera::connect()
{
+ LOGV("connect");
sp<Camera> c = new Camera();
const sp<ICameraService>& cs = getCameraService();
if (cs != 0) {
@@ -97,6 +114,7 @@ sp<Camera> Camera::connect()
void Camera::disconnect()
{
+ LOGV("disconnect");
if (mCamera != 0) {
mErrorCallback = 0;
mCamera->disconnect();
@@ -104,9 +122,24 @@ void Camera::disconnect()
}
}
+status_t Camera::reconnect()
+{
+ LOGV("reconnect");
+ if (mCamera != 0) {
+ return mCamera->connect(this);
+ }
+ return NO_INIT;
+}
+
+sp<ICamera> Camera::remote()
+{
+ return mCamera;
+}
+
// pass the buffered ISurface to the camera service
status_t Camera::setPreviewDisplay(const sp<Surface>& surface)
{
+ LOGV("setPreviewDisplay");
if (surface == 0) {
LOGE("app passed NULL surface");
return NO_INIT;
@@ -114,81 +147,105 @@ status_t Camera::setPreviewDisplay(const sp<Surface>& surface)
return mCamera->setPreviewDisplay(surface->getISurface());
}
+status_t Camera::setPreviewDisplay(const sp<ISurface>& surface)
+{
+ LOGV("setPreviewDisplay");
+ if (surface == 0) {
+ LOGE("app passed NULL surface");
+ return NO_INIT;
+ }
+ return mCamera->setPreviewDisplay(surface);
+}
+
+
// start preview mode, must call setPreviewDisplay first
status_t Camera::startPreview()
{
+ LOGV("startPreview");
return mCamera->startPreview();
}
// stop preview mode
void Camera::stopPreview()
{
+ LOGV("stopPreview");
mCamera->stopPreview();
}
status_t Camera::autoFocus()
{
+ LOGV("autoFocus");
return mCamera->autoFocus();
}
// take a picture
status_t Camera::takePicture()
{
+ LOGV("takePicture");
return mCamera->takePicture();
}
// set preview/capture parameters - key/value pairs
status_t Camera::setParameters(const String8& params)
{
+ LOGV("setParameters");
return mCamera->setParameters(params);
}
// get preview/capture parameters - key/value pairs
String8 Camera::getParameters() const
{
+ LOGV("getParameters");
String8 params = mCamera->getParameters();
return params;
}
void Camera::setAutoFocusCallback(autofocus_callback cb, void *cookie)
{
+ LOGV("setAutoFocusCallback");
mAutoFocusCallback = cb;
mAutoFocusCallbackCookie = cookie;
}
void Camera::setShutterCallback(shutter_callback cb, void *cookie)
{
+ LOGV("setShutterCallback");
mShutterCallback = cb;
mShutterCallbackCookie = cookie;
}
void Camera::setRawCallback(frame_callback cb, void *cookie)
{
+ LOGV("setRawCallback");
mRawCallback = cb;
mRawCallbackCookie = cookie;
}
void Camera::setJpegCallback(frame_callback cb, void *cookie)
{
+ LOGV("setJpegCallback");
mJpegCallback = cb;
mJpegCallbackCookie = cookie;
}
-void Camera::setFrameCallback(frame_callback cb, void *cookie)
+void Camera::setFrameCallback(frame_callback cb, void *cookie, int frame_callback_flag)
{
+ LOGV("setFrameCallback");
mFrameCallback = cb;
mFrameCallbackCookie = cookie;
- mCamera->setHasFrameCallback(cb != NULL);
+ mCamera->setFrameCallbackFlag(frame_callback_flag);
}
void Camera::setErrorCallback(error_callback cb, void *cookie)
{
+ LOGV("setErrorCallback");
mErrorCallback = cb;
mErrorCallbackCookie = cookie;
}
void Camera::autoFocusCallback(bool focused)
{
+ LOGV("autoFocusCallback");
if (mAutoFocusCallback) {
mAutoFocusCallback(focused, mAutoFocusCallbackCookie);
}
@@ -196,6 +253,7 @@ void Camera::autoFocusCallback(bool focused)
void Camera::shutterCallback()
{
+ LOGV("shutterCallback");
if (mShutterCallback) {
mShutterCallback(mShutterCallbackCookie);
}
@@ -203,6 +261,7 @@ void Camera::shutterCallback()
void Camera::rawCallback(const sp<IMemory>& picture)
{
+ LOGV("rawCallback");
if (mRawCallback) {
mRawCallback(picture, mRawCallbackCookie);
}
@@ -211,6 +270,7 @@ void Camera::rawCallback(const sp<IMemory>& picture)
// callback from camera service when image is ready
void Camera::jpegCallback(const sp<IMemory>& picture)
{
+ LOGV("jpegCallback");
if (mJpegCallback) {
mJpegCallback(picture, mJpegCallbackCookie);
}
@@ -219,6 +279,7 @@ void Camera::jpegCallback(const sp<IMemory>& picture)
// callback from camera service when video frame is ready
void Camera::frameCallback(const sp<IMemory>& frame)
{
+ LOGV("frameCallback");
if (mFrameCallback) {
mFrameCallback(frame, mFrameCallbackCookie);
}
@@ -227,19 +288,21 @@ void Camera::frameCallback(const sp<IMemory>& frame)
// callback from camera service when an error occurs in preview or takePicture
void Camera::errorCallback(status_t error)
{
+ LOGV("errorCallback");
if (mErrorCallback) {
mErrorCallback(error, mErrorCallbackCookie);
}
}
-void Camera::binderDied(const wp<IBinder>& who) {
+void Camera::binderDied(const wp<IBinder>& who) {
LOGW("ICamera died");
if (mErrorCallback) {
mErrorCallback(DEAD_OBJECT, mErrorCallbackCookie);
}
}
-void Camera::DeathNotifier::binderDied(const wp<IBinder>& who) {
+void Camera::DeathNotifier::binderDied(const wp<IBinder>& who) {
+ LOGV("binderDied");
Mutex::Autolock _l(Camera::mLock);
Camera::mCameraService.clear();
LOGW("Camera server died!");
diff --git a/libs/ui/EGLDisplaySurface.cpp b/libs/ui/EGLDisplaySurface.cpp
index ea245f5..44258a8 100644
--- a/libs/ui/EGLDisplaySurface.cpp
+++ b/libs/ui/EGLDisplaySurface.cpp
@@ -28,11 +28,15 @@
#include <cutils/log.h>
#include <cutils/atomic.h>
+#include <cutils/properties.h>
+
+#include <hardware/copybit.h>
#include <ui/SurfaceComposerClient.h>
#include <ui/DisplayInfo.h>
#include <ui/Rect.h>
#include <ui/Region.h>
+#include <ui/EGLDisplaySurface.h>
#if HAVE_ANDROID_OS
#include <linux/msm_mdp.h>
@@ -42,7 +46,6 @@
#include <pixelflinger/format.h>
-#include <ui/EGLDisplaySurface.h>
// ----------------------------------------------------------------------------
@@ -78,7 +81,12 @@ EGLDisplaySurface::EGLDisplaySurface()
mBlitEngine = 0;
egl_native_window_t::fd = mapFrameBuffer();
if (egl_native_window_t::fd >= 0) {
- mBlitEngine = copybit_init();
+
+ hw_module_t const* module;
+ if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
+ copybit_open(module, &mBlitEngine);
+ }
+
const float in2mm = 25.4f;
float refreshRate = 1000000000000000LLU / (
float( mInfo.upper_margin + mInfo.lower_margin + mInfo.yres )
@@ -108,7 +116,7 @@ EGLDisplaySurface::EGLDisplaySurface()
EGLDisplaySurface::~EGLDisplaySurface()
{
magic = 0;
- copybit_term(mBlitEngine);
+ copybit_close(mBlitEngine);
mBlitEngine = 0;
close(egl_native_window_t::fd);
munmap(mFb[0].data, mSize);
@@ -147,9 +155,6 @@ void EGLDisplaySurface::setSwapRectangle(int l, int t, int w, int h)
uint32_t EGLDisplaySurface::swapBuffers()
{
- if (!(mFlags & PAGE_FLIP))
- return 0;
-
#define SHOW_FPS 0
#if SHOW_FPS
nsecs_t now = systemTime();
@@ -171,6 +176,11 @@ uint32_t EGLDisplaySurface::swapBuffers()
}
}
#endif
+ /* If we can't do the page_flip, just copy the back buffer to the front */
+ if (!(mFlags & PAGE_FLIP)) {
+ memcpy(mFb[0].data, mFb[1].data, mInfo.xres*mInfo.yres*2);
+ return 0;
+ }
// do the actual flip
mIndex = 1 - mIndex;
@@ -192,7 +202,7 @@ uint32_t EGLDisplaySurface::swapBuffers()
* with msm7k.
*/
if (egl_native_window_t::memory_type == NATIVE_MEMORY_TYPE_GPU && oem[0] && mBlitEngine) {
- copybit_t *copybit = mBlitEngine;
+ copybit_device_t *copybit = mBlitEngine;
copybit_rect_t sdrect = { 0, 0,
egl_native_window_t::width, egl_native_window_t::height };
copybit_image_t dst = {
@@ -273,6 +283,12 @@ void EGLDisplaySurface::copyFrontToBack(const Region& copyback)
} else
#endif
{
+ /* no extra copy needed since we copied back to front instead of
+ * flipping */
+ if (!(mFlags & PAGE_FLIP)) {
+ return;
+ }
+
Region::iterator iterator(copyback);
if (iterator) {
Rect r;
@@ -373,12 +389,11 @@ status_t EGLDisplaySurface::mapFrameBuffer()
// bleagh, bad info from the driver
refreshRate = 60*1000; // 60 Hz
}
-
if (int(info.width) <= 0 || int(info.height) <= 0) {
// the driver doesn't return that information
// default to 160 dpi
- info.width = 51;
- info.height = 38;
+ info.width = ((info.xres * 25.4f)/160.0f + 0.5f);
+ info.height = ((info.yres * 25.4f)/160.0f + 0.5f);
}
float xdpi = (info.xres * 25.4f) / info.width;
diff --git a/libs/ui/EGLNativeWindowSurface.cpp b/libs/ui/EGLNativeWindowSurface.cpp
index 0b6afc0..d55fb70 100644
--- a/libs/ui/EGLNativeWindowSurface.cpp
+++ b/libs/ui/EGLNativeWindowSurface.cpp
@@ -163,7 +163,12 @@ void EGLNativeWindowSurface::connect()
egl_native_window_t::format = info.format;
egl_native_window_t::base = intptr_t(info.base);
egl_native_window_t::offset = intptr_t(info.bits) - intptr_t(info.base);
- egl_native_window_t::memory_type = mSurface->getMemoryType();
+ // FIXME: egl_native_window_t::memory_type used to be set from
+ // mSurface, but we wanted to break this dependency. We set it to
+ // GPU because the software rendered doesn't care, but the h/w
+ // accelerator needs it. Eventually, this value should go away
+ // completely, since memory will be managed by OpenGL.
+ egl_native_window_t::memory_type = NATIVE_MEMORY_TYPE_GPU;
egl_native_window_t::fd = 0;
}
}
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index f0c77ba..abe7407 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -315,9 +315,8 @@ bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
}
//printf("poll %d, returned %d\n", mFDCount, pollres);
- if(mFDs[0].revents & POLLIN) {
- read_notify(mFDs[0].fd);
- }
+
+ // mFDs[0] is used for inotify, so process regular events starting at mFDs[1]
for(i = 1; i < mFDCount; i++) {
if(mFDs[i].revents) {
LOGV("revents for %d = 0x%08x", i, mFDs[i].revents);
@@ -357,6 +356,12 @@ bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
}
}
}
+
+ // read_notify() will modify mFDs and mFDCount, so this must be done after
+ // processing all other events.
+ if(mFDs[0].revents & POLLIN) {
+ read_notify(mFDs[0].fd);
+ }
}
}
@@ -607,7 +612,7 @@ int EventHub::open_device(const char *deviceName)
sprintf(propName, "hw.keyboards.%u.devname", publicID);
property_set(propName, devname);
- LOGI("New keyboard: publicID=%d device->id=%d devname='%s propName='%s' keylayout='%s'\n",
+ LOGI("New keyboard: publicID=%d device->id=%d devname='%s' propName='%s' keylayout='%s'\n",
publicID, device->id, devname, propName, keylayoutFilename);
}
diff --git a/libs/ui/ICamera.cpp b/libs/ui/ICamera.cpp
index 420bb49..6a2dc6b 100644
--- a/libs/ui/ICamera.cpp
+++ b/libs/ui/ICamera.cpp
@@ -2,41 +2,40 @@
**
** Copyright 2008, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ICamera"
+#include <utils/Log.h>
#include <stdint.h>
#include <sys/types.h>
-
#include <utils/Parcel.h>
-
#include <ui/ICamera.h>
-#define LOG_TAG "@@@@@@@@@@@ CAMERA @@@@@@@@@@@"
-#include <utils/Log.h>
-
namespace android {
enum {
DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
SET_PREVIEW_DISPLAY,
- SET_HAS_FRAME_CALLBACK,
+ SET_FRAME_CALLBACK_FLAG,
START_PREVIEW,
STOP_PREVIEW,
AUTO_FOCUS,
TAKE_PICTURE,
SET_PARAMETERS,
- GET_PARAMETERS
+ GET_PARAMETERS,
+ CONNECT
};
class BpCamera: public BpInterface<ICamera>
@@ -50,6 +49,7 @@ public:
// disconnect from camera service
void disconnect()
{
+ LOGV("disconnect");
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
remote()->transact(DISCONNECT, data, &reply);
@@ -58,25 +58,29 @@ public:
// pass the buffered ISurface to the camera service
status_t setPreviewDisplay(const sp<ISurface>& surface)
{
+ LOGV("setPreviewDisplay");
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
data.writeStrongBinder(surface->asBinder());
remote()->transact(SET_PREVIEW_DISPLAY, data, &reply);
return reply.readInt32();
}
-
- // tell the service whether to callback with each preview frame
- void setHasFrameCallback(bool installed)
+
+ // set the frame callback flag to affect how the received frames from
+ // preview are handled.
+ void setFrameCallbackFlag(int frame_callback_flag)
{
+ LOGV("setFrameCallbackFlag(%d)", frame_callback_flag);
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
- data.writeInt32((int32_t)installed);
- remote()->transact(SET_HAS_FRAME_CALLBACK, data, &reply);
+ data.writeInt32(frame_callback_flag);
+ remote()->transact(SET_FRAME_CALLBACK_FLAG, data, &reply);
}
// start preview mode, must call setPreviewDisplay first
status_t startPreview()
{
+ LOGV("startPreview");
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
remote()->transact(START_PREVIEW, data, &reply);
@@ -86,6 +90,7 @@ public:
// stop preview mode
void stopPreview()
{
+ LOGV("stopPreview");
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
remote()->transact(STOP_PREVIEW, data, &reply);
@@ -94,6 +99,7 @@ public:
// auto focus
status_t autoFocus()
{
+ LOGV("autoFocus");
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
remote()->transact(AUTO_FOCUS, data, &reply);
@@ -104,6 +110,7 @@ public:
// take a picture - returns an IMemory (ref-counted mmap)
status_t takePicture()
{
+ LOGV("takePicture");
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
remote()->transact(TAKE_PICTURE, data, &reply);
@@ -114,6 +121,7 @@ public:
// set preview/capture parameters - key/value pairs
status_t setParameters(const String8& params)
{
+ LOGV("setParameters");
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
data.writeString8(params);
@@ -124,11 +132,20 @@ public:
// get preview/capture parameters - key/value pairs
String8 getParameters() const
{
+ LOGV("getParameters");
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
remote()->transact(GET_PARAMETERS, data, &reply);
return reply.readString8();
}
+ virtual status_t connect(const sp<ICameraClient>& cameraClient)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ data.writeStrongBinder(cameraClient->asBinder());
+ remote()->transact(CONNECT, data, &reply);
+ return reply.readInt32();
+ }
};
IMPLEMENT_META_INTERFACE(Camera, "android.hardware.ICamera");
@@ -146,53 +163,68 @@ status_t BnCamera::onTransact(
{
switch(code) {
case DISCONNECT: {
+ LOGV("DISCONNECT");
CHECK_INTERFACE(ICamera, data, reply);
disconnect();
return NO_ERROR;
} break;
case SET_PREVIEW_DISPLAY: {
+ LOGV("SET_PREVIEW_DISPLAY");
CHECK_INTERFACE(ICamera, data, reply);
sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder());
reply->writeInt32(setPreviewDisplay(surface));
return NO_ERROR;
} break;
- case SET_HAS_FRAME_CALLBACK: {
+ case SET_FRAME_CALLBACK_FLAG: {
+ LOGV("SET_FRAME_CALLBACK_TYPE");
CHECK_INTERFACE(ICamera, data, reply);
- bool installed = (bool)data.readInt32();
- setHasFrameCallback(installed);
+ int frame_callback_flag = data.readInt32();
+ setFrameCallbackFlag(frame_callback_flag);
return NO_ERROR;
} break;
case START_PREVIEW: {
+ LOGV("START_PREVIEW");
CHECK_INTERFACE(ICamera, data, reply);
reply->writeInt32(startPreview());
return NO_ERROR;
} break;
case STOP_PREVIEW: {
+ LOGV("STOP_PREVIEW");
CHECK_INTERFACE(ICamera, data, reply);
stopPreview();
return NO_ERROR;
} break;
case AUTO_FOCUS: {
+ LOGV("AUTO_FOCUS");
CHECK_INTERFACE(ICamera, data, reply);
reply->writeInt32(autoFocus());
return NO_ERROR;
} break;
case TAKE_PICTURE: {
+ LOGV("TAKE_PICTURE");
CHECK_INTERFACE(ICamera, data, reply);
reply->writeInt32(takePicture());
return NO_ERROR;
} break;
case SET_PARAMETERS: {
+ LOGV("SET_PARAMETERS");
CHECK_INTERFACE(ICamera, data, reply);
- String8 params(data.readString8());
- reply->writeInt32(setParameters(params));
+ String8 params(data.readString8());
+ reply->writeInt32(setParameters(params));
return NO_ERROR;
} break;
case GET_PARAMETERS: {
+ LOGV("GET_PARAMETERS");
CHECK_INTERFACE(ICamera, data, reply);
reply->writeString8(getParameters());
return NO_ERROR;
} break;
+ case CONNECT: {
+ CHECK_INTERFACE(ICamera, data, reply);
+ sp<ICameraClient> cameraClient = interface_cast<ICameraClient>(data.readStrongBinder());
+ reply->writeInt32(connect(cameraClient));
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/ui/ICameraClient.cpp b/libs/ui/ICameraClient.cpp
index 3737034..c5d6d52 100644
--- a/libs/ui/ICameraClient.cpp
+++ b/libs/ui/ICameraClient.cpp
@@ -15,9 +15,11 @@
** limitations under the License.
*/
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ICameraClient"
+#include <utils/Log.h>
#include <stdint.h>
#include <sys/types.h>
-
#include <ui/ICameraClient.h>
namespace android {
@@ -42,6 +44,7 @@ public:
// callback to let the app know the shutter has closed, ideal for playing the shutter sound
void shutterCallback()
{
+ LOGV("shutterCallback");
Parcel data, reply;
data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
remote()->transact(SHUTTER_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
@@ -50,6 +53,7 @@ public:
// callback from camera service to app with picture data
void rawCallback(const sp<IMemory>& picture)
{
+ LOGV("rawCallback");
Parcel data, reply;
data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
data.writeStrongBinder(picture->asBinder());
@@ -59,6 +63,7 @@ public:
// callback from camera service to app with picture data
void jpegCallback(const sp<IMemory>& picture)
{
+ LOGV("jpegCallback");
Parcel data, reply;
data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
data.writeStrongBinder(picture->asBinder());
@@ -68,6 +73,7 @@ public:
// callback from camera service to app with video frame data
void frameCallback(const sp<IMemory>& frame)
{
+ LOGV("frameCallback");
Parcel data, reply;
data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
data.writeStrongBinder(frame->asBinder());
@@ -77,6 +83,7 @@ public:
// callback from camera service to app to report error
void errorCallback(status_t error)
{
+ LOGV("errorCallback");
Parcel data, reply;
data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
data.writeInt32(error);
@@ -86,6 +93,7 @@ public:
// callback from camera service to app to report autofocus completion
void autoFocusCallback(bool focused)
{
+ LOGV("autoFocusCallback");
Parcel data, reply;
data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
data.writeInt32(focused);
@@ -108,35 +116,41 @@ status_t BnCameraClient::onTransact(
{
switch(code) {
case SHUTTER_CALLBACK: {
+ LOGV("SHUTTER_CALLBACK");
CHECK_INTERFACE(ICameraClient, data, reply);
shutterCallback();
return NO_ERROR;
} break;
case RAW_CALLBACK: {
+ LOGV("RAW_CALLBACK");
CHECK_INTERFACE(ICameraClient, data, reply);
sp<IMemory> picture = interface_cast<IMemory>(data.readStrongBinder());
rawCallback(picture);
return NO_ERROR;
} break;
case JPEG_CALLBACK: {
+ LOGV("JPEG_CALLBACK");
CHECK_INTERFACE(ICameraClient, data, reply);
sp<IMemory> picture = interface_cast<IMemory>(data.readStrongBinder());
jpegCallback(picture);
return NO_ERROR;
} break;
case FRAME_CALLBACK: {
+ LOGV("FRAME_CALLBACK");
CHECK_INTERFACE(ICameraClient, data, reply);
sp<IMemory> frame = interface_cast<IMemory>(data.readStrongBinder());
frameCallback(frame);
return NO_ERROR;
} break;
case ERROR_CALLBACK: {
+ LOGV("ERROR_CALLBACK");
CHECK_INTERFACE(ICameraClient, data, reply);
status_t error = data.readInt32();
errorCallback(error);
return NO_ERROR;
} break;
case AUTOFOCUS_CALLBACK: {
+ LOGV("AUTOFOCUS_CALLBACK");
CHECK_INTERFACE(ICameraClient, data, reply);
bool focused = (bool)data.readInt32();
autoFocusCallback(focused);
diff --git a/libs/ui/IOverlay.cpp b/libs/ui/IOverlay.cpp
new file mode 100644
index 0000000..59d1ea0
--- /dev/null
+++ b/libs/ui/IOverlay.cpp
@@ -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.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+#include <utils/IInterface.h>
+
+#include <ui/IOverlay.h>
+
+namespace android {
+
+enum {
+ DESTROY = IBinder::FIRST_CALL_TRANSACTION, // one-way transaction
+ SWAP_BUFFERS,
+};
+
+class BpOverlay : public BpInterface<IOverlay>
+{
+public:
+ BpOverlay(const sp<IBinder>& impl)
+ : BpInterface<IOverlay>(impl)
+ {
+ }
+
+ virtual void destroy()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOverlay::getInterfaceDescriptor());
+ remote()->transact(DESTROY, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+
+ virtual ssize_t swapBuffers()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOverlay::getInterfaceDescriptor());
+ remote()->transact(SWAP_BUFFERS, data, &reply);
+ return reply.readInt32();
+ }
+};
+
+IMPLEMENT_META_INTERFACE(Overlay, "android.ui.IOverlay");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+ LOGW("Call incorrectly routed to " #interface); \
+ return PERMISSION_DENIED; \
+ } } while (0)
+
+status_t BnOverlay::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case DESTROY: {
+ CHECK_INTERFACE(IOverlay, data, reply);
+ destroy();
+ return NO_ERROR;
+ } break;
+ case SWAP_BUFFERS: {
+ CHECK_INTERFACE(IOverlay, data, reply);
+ ssize_t offset = swapBuffers();
+ reply->writeInt32(offset);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+}; // namespace android
diff --git a/libs/ui/ISurface.cpp b/libs/ui/ISurface.cpp
index 817f4d9..c1c9596 100644
--- a/libs/ui/ISurface.cpp
+++ b/libs/ui/ISurface.cpp
@@ -22,6 +22,7 @@
#include <utils/IMemory.h>
#include <ui/ISurface.h>
+#include <ui/Overlay.h>
namespace android {
@@ -30,6 +31,7 @@ enum {
REGISTER_BUFFERS = IBinder::FIRST_CALL_TRANSACTION,
UNREGISTER_BUFFERS,
POST_BUFFER, // one-way transaction
+ CREATE_OVERLAY,
};
class BpSurface : public BpInterface<ISurface>
@@ -70,6 +72,18 @@ public:
data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
remote()->transact(UNREGISTER_BUFFERS, data, &reply);
}
+
+ virtual sp<Overlay> createOverlay(
+ uint32_t w, uint32_t h, int32_t format)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
+ data.writeInt32(w);
+ data.writeInt32(h);
+ data.writeInt32(format);
+ remote()->transact(CREATE_OVERLAY, data, &reply);
+ return Overlay::readFromParcel(reply);
+ }
};
IMPLEMENT_META_INTERFACE(Surface, "android.ui.ISurface");
@@ -109,6 +123,14 @@ status_t BnSurface::onTransact(
postBuffer(offset);
return NO_ERROR;
} break;
+ case CREATE_OVERLAY: {
+ CHECK_INTERFACE(ISurface, data, reply);
+ int w = data.readInt32();
+ int h = data.readInt32();
+ int f = data.readInt32();
+ sp<Overlay> o = createOverlay(w, h, w);
+ return Overlay::writeToParcel(reply, o);
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/ui/ISurfaceFlingerClient.cpp b/libs/ui/ISurfaceFlingerClient.cpp
index 9444af7..dd6a798 100644
--- a/libs/ui/ISurfaceFlingerClient.cpp
+++ b/libs/ui/ISurfaceFlingerClient.cpp
@@ -82,7 +82,7 @@ public:
data.writeInt32(format);
data.writeInt32(flags);
remote()->transact(CREATE_SURFACE, data, &reply);
- params->readFromParcel(data);
+ params->readFromParcel(reply);
return interface_cast<ISurface>(reply.readStrongBinder());
}
@@ -191,7 +191,6 @@ status_t ISurfaceFlingerClient::surface_data_t::readFromParcel(const Parcel& par
{
token = parcel.readInt32();
identity = parcel.readInt32();
- type = parcel.readInt32();
heap[0] = interface_cast<IMemoryHeap>(parcel.readStrongBinder());
heap[1] = interface_cast<IMemoryHeap>(parcel.readStrongBinder());
return NO_ERROR;
@@ -201,7 +200,6 @@ status_t ISurfaceFlingerClient::surface_data_t::writeToParcel(Parcel* parcel) co
{
parcel->writeInt32(token);
parcel->writeInt32(identity);
- parcel->writeInt32(type);
parcel->writeStrongBinder(heap[0]!=0 ? heap[0]->asBinder() : NULL);
parcel->writeStrongBinder(heap[1]!=0 ? heap[1]->asBinder() : NULL);
return NO_ERROR;
diff --git a/libs/ui/Overlay.cpp b/libs/ui/Overlay.cpp
new file mode 100644
index 0000000..2267c3e
--- /dev/null
+++ b/libs/ui/Overlay.cpp
@@ -0,0 +1,145 @@
+/*
+ * 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 <utils/IMemory.h>
+#include <utils/Parcel.h>
+
+#include <ui/IOverlay.h>
+#include <ui/Overlay.h>
+
+namespace android {
+
+Overlay::Overlay(overlay_handle_t* handle,
+ const sp<IOverlay>& o, const sp<IMemoryHeap>& heap,
+ uint32_t w, uint32_t h, int32_t f, uint32_t ws, uint32_t hs)
+ : mOverlay(o), mHeap(heap), mCurrentBufferOffset(0), mOverlayHandle(handle),
+ mWidth(w), mHeight(h), mFormat(f), mWidthStride(ws), mHeightStride(hs)
+{
+}
+
+Overlay::Overlay(overlay_t* overlay,
+ const sp<IOverlay>& o, const sp<IMemoryHeap>& heap)
+ : mOverlay(o), mHeap(heap)
+{
+ mCurrentBufferOffset = 0;
+ mOverlayHandle = overlay->getHandleRef(overlay);
+ mWidth = overlay->w;
+ mHeight = overlay->h;
+ mFormat = overlay->format;
+ mWidthStride = overlay->w_stride;
+ mHeightStride = overlay->h_stride;
+}
+
+
+Overlay::~Overlay() {
+}
+
+void Overlay::destroy() {
+ mOverlay->destroy();
+}
+
+status_t Overlay::swapBuffers() {
+ ssize_t result = mOverlay->swapBuffers();
+ if (result < 0)
+ return status_t(result);
+ mCurrentBufferOffset = result;
+ return NO_ERROR;
+}
+
+overlay_handle_t const* Overlay::getHandleRef() const {
+ return mOverlayHandle;
+}
+
+size_t Overlay::getBufferOffset() const {
+ return mCurrentBufferOffset;
+}
+
+sp<IMemoryHeap> Overlay::getHeap() const {
+ return mHeap;
+}
+
+uint32_t Overlay::getWidth() const {
+ return mWidth;
+}
+
+uint32_t Overlay::getHeight() const {
+ return mHeight;
+}
+
+int32_t Overlay::getFormat() const {
+ return mFormat;
+}
+
+int32_t Overlay::getWidthStride() const {
+ return mWidthStride;
+}
+
+int32_t Overlay::getHeightStride() const {
+ return mHeightStride;
+}
+
+sp<Overlay> Overlay::readFromParcel(const Parcel& data) {
+ sp<Overlay> result;
+ sp<IOverlay> overlay = IOverlay::asInterface(data.readStrongBinder());
+ if (overlay != NULL) {
+ sp<IMemoryHeap> heap = IMemoryHeap::asInterface(data.readStrongBinder());
+ uint32_t w = data.readInt32();
+ uint32_t h = data.readInt32();
+ uint32_t f = data.readInt32();
+ uint32_t ws = data.readInt32();
+ uint32_t hs = data.readInt32();
+ /* FIXME: handles should be promoted to "real" API and be handled by
+ * the framework */
+ int numfd = data.readInt32();
+ int numint = data.readInt32();
+ overlay_handle_t* handle = (overlay_handle_t*)malloc(
+ sizeof(overlay_handle_t) + numint*sizeof(int));
+ for (int i=0 ; i<numfd ; i++)
+ handle->fds[i] = data.readFileDescriptor();
+ for (int i=0 ; i<numint ; i++)
+ handle->data[i] = data.readInt32();
+ result = new Overlay(handle, overlay, heap, w, h, f, ws, hs);
+ }
+ return result;
+}
+
+status_t Overlay::writeToParcel(Parcel* reply, const sp<Overlay>& o) {
+ if (o != NULL) {
+ reply->writeStrongBinder(o->mOverlay->asBinder());
+ reply->writeStrongBinder(o->mHeap->asBinder());
+ reply->writeInt32(o->mWidth);
+ reply->writeInt32(o->mHeight);
+ reply->writeInt32(o->mFormat);
+ reply->writeInt32(o->mWidthStride);
+ reply->writeInt32(o->mHeightStride);
+ /* FIXME: handles should be promoted to "real" API and be handled by
+ * the framework */
+ reply->writeInt32(o->mOverlayHandle->numFds);
+ reply->writeInt32(o->mOverlayHandle->numInts);
+ for (int i=0 ; i<o->mOverlayHandle->numFds ; i++)
+ reply->writeFileDescriptor(o->mOverlayHandle->fds[i]);
+ for (int i=0 ; i<o->mOverlayHandle->numInts ; i++)
+ reply->writeInt32(o->mOverlayHandle->data[i]);
+ } else {
+ reply->writeStrongBinder(NULL);
+ }
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp
index 0a9aaad..4ea9ae2 100644
--- a/libs/ui/Surface.cpp
+++ b/libs/ui/Surface.cpp
@@ -47,7 +47,7 @@ Surface::Surface(const sp<SurfaceComposerClient>& client,
const ISurfaceFlingerClient::surface_data_t& data,
uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
bool owner)
- : mClient(client), mSurface(surface), mMemoryType(data.type),
+ : mClient(client), mSurface(surface),
mToken(data.token), mIdentity(data.identity),
mFormat(format), mFlags(flags), mOwner(owner)
{
@@ -67,7 +67,6 @@ Surface::Surface(Surface const* rhs)
mSurface = rhs->mSurface;
mHeap[0] = rhs->mHeap[0];
mHeap[1] = rhs->mHeap[1];
- mMemoryType = rhs->mMemoryType;
mFormat = rhs->mFormat;
mFlags = rhs->mFlags;
mSurfaceHeapBase[0] = rhs->mSurfaceHeapBase[0];
@@ -186,7 +185,6 @@ sp<Surface> Surface::readFromParcel(Parcel* parcel)
sp<ISurface> surface = interface_cast<ISurface>(parcel->readStrongBinder());
data.heap[0] = interface_cast<IMemoryHeap>(parcel->readStrongBinder());
data.heap[1] = interface_cast<IMemoryHeap>(parcel->readStrongBinder());
- data.type = parcel->readInt32();
data.token = parcel->readInt32();
data.identity = parcel->readInt32();
PixelFormat format = parcel->readInt32();
@@ -207,7 +205,6 @@ status_t Surface::writeToParcel(const sp<Surface>& surface, Parcel* parcel)
sp<SurfaceComposerClient> client;
sp<ISurface> sur;
sp<IMemoryHeap> heap[2];
- int type = 0;
if (surface->isValid()) {
token = surface->mToken;
identity = surface->mIdentity;
@@ -215,7 +212,6 @@ status_t Surface::writeToParcel(const sp<Surface>& surface, Parcel* parcel)
sur = surface->mSurface;
heap[0] = surface->mHeap[0];
heap[1] = surface->mHeap[1];
- type = surface->mMemoryType;
format = surface->mFormat;
flags = surface->mFlags;
}
@@ -223,7 +219,6 @@ status_t Surface::writeToParcel(const sp<Surface>& surface, Parcel* parcel)
parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
parcel->writeStrongBinder(heap[0]!=0 ? heap[0]->asBinder() : NULL);
parcel->writeStrongBinder(heap[1]!=0 ? heap[1]->asBinder() : NULL);
- parcel->writeInt32(type);
parcel->writeInt32(token);
parcel->writeInt32(identity);
parcel->writeInt32(format);
diff --git a/libs/ui/Time.cpp b/libs/ui/Time.cpp
index c98667f..b553913 100644
--- a/libs/ui/Time.cpp
+++ b/libs/ui/Time.cpp
@@ -85,10 +85,10 @@ Time::switchTimezone(const char* timezone)
}
String8
-Time::format(const char *format) const
+Time::format(const char *format, const struct strftime_locale *locale) const
{
char buf[257];
- int n = strftime(buf, 257, format, &(this->t));
+ int n = strftime_tz(buf, 257, format, &(this->t), locale);
if (n > 0) {
return String8(buf);
} else {
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 4a68dc1..cdb8ca2 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -139,6 +139,14 @@ LOCAL_SHARED_LIBRARIES := \
liblog \
libcutils
+ifneq ($(TARGET_SIMULATOR),true)
+ifeq ($(TARGET_OS)-$(TARGET_ARCH),linux-x86)
+# This is needed on x86 to bring in dl_iterate_phdr for CallStack.cpp
+LOCAL_SHARED_LIBRARIES += \
+ libdl
+endif # linux-x86
+endif # sim
+
LOCAL_MODULE:= libutils
#LOCAL_CFLAGS+=
diff --git a/libs/utils/CallStack.cpp b/libs/utils/CallStack.cpp
index 4968666..26fb22a 100644
--- a/libs/utils/CallStack.cpp
+++ b/libs/utils/CallStack.cpp
@@ -79,35 +79,35 @@ int backtrace(const void** addrs, size_t ignore, size_t size)
/*****************************************************************************/
static
-const char *lookup_symbol(const void* addr, uint32_t *offset, char* name, size_t bufSize)
+const char *lookup_symbol(const void* addr, void **offset, char* name, size_t bufSize)
{
#if HAVE_DLADDR
- Dl_info info;
- if (dladdr(addr, &info)) {
- *offset = (uint32_t)info.dli_saddr;
- return info.dli_sname;
- }
+ Dl_info info;
+ if (dladdr(addr, &info)) {
+ *offset = info.dli_saddr;
+ return info.dli_sname;
+ }
#endif
- return NULL;
+ return NULL;
}
static
int32_t linux_gcc_demangler(const char *mangled_name, char *unmangled_name, size_t buffersize)
{
- size_t out_len = 0;
+ size_t out_len = 0;
#if HAVE_CXXABI
- int status = 0;
- char *demangled = abi::__cxa_demangle(mangled_name, 0, &out_len, &status);
- if (status == 0) {
- // OK
- if (out_len < buffersize) memcpy(unmangled_name, demangled, out_len);
- else out_len = 0;
- free(demangled);
- } else {
- out_len = 0;
- }
+ int status = 0;
+ char *demangled = abi::__cxa_demangle(mangled_name, 0, &out_len, &status);
+ if (status == 0) {
+ // OK
+ if (out_len < buffersize) memcpy(unmangled_name, demangled, out_len);
+ else out_len = 0;
+ free(demangled);
+ } else {
+ out_len = 0;
+ }
#endif
- return out_len;
+ return out_len;
}
/*****************************************************************************/
@@ -115,12 +115,12 @@ int32_t linux_gcc_demangler(const char *mangled_name, char *unmangled_name, size
class MapInfo {
struct mapinfo {
struct mapinfo *next;
- unsigned start;
- unsigned end;
+ uint64_t start;
+ uint64_t end;
char name[];
};
- const char *map_to_name(unsigned pc, const char* def) {
+ const char *map_to_name(uint64_t pc, const char* def) {
mapinfo* mi = getMapInfoList();
while(mi) {
if ((pc >= mi->start) && (pc < mi->end))
@@ -139,8 +139,8 @@ class MapInfo {
if (line[20] != 'x') return 0;
mi = (mapinfo*)malloc(sizeof(mapinfo) + (len - 47));
if (mi == 0) return 0;
- mi->start = strtoul(line, 0, 16);
- mi->end = strtoul(line + 9, 0, 16);
+ mi->start = strtoull(line, 0, 16);
+ mi->end = strtoull(line + 9, 0, 16);
mi->next = 0;
strcpy(mi->name, line + 49);
return mi;
@@ -184,7 +184,7 @@ public:
}
static const char *mapAddressToName(const void* pc, const char* def) {
- return sMapInfo.map_to_name((unsigned)pc, def);
+ return sMapInfo.map_to_name((uint64_t)pc, def);
}
};
@@ -278,7 +278,7 @@ String8 CallStack::toStringSingleLevel(const char* prefix, int32_t level) const
char tmp[256];
char tmp1[32];
char tmp2[32];
- uint32_t offs;
+ void *offs;
const void* ip = mStack[level];
if (!ip) return res;
@@ -291,14 +291,14 @@ String8 CallStack::toStringSingleLevel(const char* prefix, int32_t level) const
if (name) {
if (linux_gcc_demangler(name, tmp, 256) != 0)
name = tmp;
- snprintf(tmp1, 32, "0x%08x: <", (size_t)ip);
- snprintf(tmp2, 32, ">+0x%08x", offs);
+ snprintf(tmp1, 32, "0x%p: <", ip);
+ snprintf(tmp2, 32, ">+0x%p", offs);
res.append(tmp1);
res.append(name);
res.append(tmp2);
} else {
name = MapInfo::mapAddressToName(ip, "<unknown>");
- snprintf(tmp, 256, "pc %08x %s", (size_t)ip, name);
+ snprintf(tmp, 256, "pc %p %s", ip, name);
res.append(tmp);
}
res.append("\n");
diff --git a/libs/utils/IPCThreadState.cpp b/libs/utils/IPCThreadState.cpp
index ca49d9a..04ae142 100644
--- a/libs/utils/IPCThreadState.cpp
+++ b/libs/utils/IPCThreadState.cpp
@@ -391,6 +391,29 @@ void IPCThreadState::joinThreadPool(bool isMain)
status_t result;
do {
int32_t cmd;
+
+ // When we've cleared the incoming command queue, process any pending derefs
+ if (mIn.dataPosition() >= mIn.dataSize()) {
+ size_t numPending = mPendingWeakDerefs.size();
+ if (numPending > 0) {
+ for (size_t i = 0; i < numPending; i++) {
+ RefBase::weakref_type* refs = mPendingWeakDerefs[i];
+ refs->decWeak(mProcess.get());
+ }
+ mPendingWeakDerefs.clear();
+ }
+
+ numPending = mPendingStrongDerefs.size();
+ if (numPending > 0) {
+ for (size_t i = 0; i < numPending; i++) {
+ BBinder* obj = mPendingStrongDerefs[i];
+ obj->decStrong(mProcess.get());
+ }
+ mPendingStrongDerefs.clear();
+ }
+ }
+
+ // now get the next command to be processed, waiting if necessary
result = talkWithDriver();
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
@@ -832,7 +855,7 @@ status_t IPCThreadState::executeCommand(int32_t cmd)
LOG_REMOTEREFS("BR_RELEASE from driver on %p", obj);
obj->printRefs();
}
- obj->decStrong(mProcess.get());
+ mPendingStrongDerefs.push(obj);
break;
case BR_INCREFS:
@@ -853,7 +876,7 @@ status_t IPCThreadState::executeCommand(int32_t cmd)
//LOG_ASSERT(refs->refBase() == obj,
// "BR_DECREFS: object %p does not match cookie %p (expected %p)",
// refs, obj, refs->refBase());
- refs->decWeak(mProcess.get());
+ mPendingWeakDerefs.push(refs);
break;
case BR_ATTEMPT_ACQUIRE:
diff --git a/libs/utils/LogSocket.cpp b/libs/utils/LogSocket.cpp
index e64f794..55c1b99 100644
--- a/libs/utils/LogSocket.cpp
+++ b/libs/utils/LogSocket.cpp
@@ -16,7 +16,7 @@
#ifndef HAVE_WINSOCK
-#define SOCKETLOG
+//#define SOCKETLOG
#endif
#ifdef SOCKETLOG
diff --git a/libs/utils/MemoryDealer.cpp b/libs/utils/MemoryDealer.cpp
index e6d1d18..cf8201b 100644
--- a/libs/utils/MemoryDealer.cpp
+++ b/libs/utils/MemoryDealer.cpp
@@ -387,21 +387,23 @@ SimpleMemory::~SimpleMemory()
start = (start + pagesize-1) & ~(pagesize-1);
end &= ~(pagesize-1);
- void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + start);
- size_t size = end-start;
+ if (start < end) {
+ void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + start);
+ size_t size = end-start;
#ifndef NDEBUG
- memset(start_ptr, 0xdf, size);
+ memset(start_ptr, 0xdf, size);
#endif
-
-// MADV_REMOVE is not defined on Dapper based Goobuntu
+
+ // MADV_REMOVE is not defined on Dapper based Goobuntu
#ifdef MADV_REMOVE
- if (size) {
- int err = madvise(start_ptr, size, MADV_REMOVE);
- LOGW_IF(err, "madvise(%p, %u, MADV_REMOVE) returned %s",
- start_ptr, size, err<0 ? strerror(errno) : "Ok");
- }
+ if (size) {
+ int err = madvise(start_ptr, size, MADV_REMOVE);
+ LOGW_IF(err, "madvise(%p, %u, MADV_REMOVE) returned %s",
+ start_ptr, size, err<0 ? strerror(errno) : "Ok");
+ }
#endif
+ }
}
}; // namespace android
diff --git a/libs/utils/MemoryHeapPmem.cpp b/libs/utils/MemoryHeapPmem.cpp
index 1e5a1cc..eba2b30 100644
--- a/libs/utils/MemoryHeapPmem.cpp
+++ b/libs/utils/MemoryHeapPmem.cpp
@@ -38,9 +38,20 @@ namespace android {
// ---------------------------------------------------------------------------
-class MemoryHeapPmem;
+MemoryHeapPmem::MemoryPmem::MemoryPmem(const sp<MemoryHeapPmem>& heap)
+ : BnMemory(), mClientHeap(heap)
+{
+}
+
+MemoryHeapPmem::MemoryPmem::~MemoryPmem() {
+ if (mClientHeap != NULL) {
+ mClientHeap->remove(this);
+ }
+}
-class SubRegionMemory : public BnMemory {
+// ---------------------------------------------------------------------------
+
+class SubRegionMemory : public MemoryHeapPmem::MemoryPmem {
public:
SubRegionMemory(const sp<MemoryHeapPmem>& heap, ssize_t offset, size_t size);
virtual ~SubRegionMemory();
@@ -50,15 +61,14 @@ private:
void revoke();
size_t mSize;
ssize_t mOffset;
- sp<MemoryHeapPmem> mClientHeap;
};
SubRegionMemory::SubRegionMemory(const sp<MemoryHeapPmem>& heap,
ssize_t offset, size_t size)
- : mSize(size), mOffset(offset), mClientHeap(heap)
+ : MemoryHeapPmem::MemoryPmem(heap), mSize(size), mOffset(offset)
{
#ifndef NDEBUG
- void* const start_ptr = (void*)(intptr_t(mClientHeap->base()) + offset);
+ void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + offset);
memset(start_ptr, 0xda, size);
#endif
@@ -80,7 +90,7 @@ sp<IMemoryHeap> SubRegionMemory::getMemory(ssize_t* offset, size_t* size) const
{
if (offset) *offset = mOffset;
if (size) *size = mSize;
- return mClientHeap;
+ return getHeap();
}
SubRegionMemory::~SubRegionMemory()
@@ -98,8 +108,9 @@ void SubRegionMemory::revoke()
// promote() it.
#if HAVE_ANDROID_OS
- if (mClientHeap != NULL) {
- int our_fd = mClientHeap->heapID();
+ if (mSize != NULL) {
+ const sp<MemoryHeapPmem>& heap(getHeap());
+ int our_fd = heap->heapID();
struct pmem_region sub;
sub.offset = mOffset;
sub.len = mSize;
@@ -107,7 +118,7 @@ void SubRegionMemory::revoke()
LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
"mFD=%d, sub.offset=%lu, sub.size=%lu",
strerror(errno), our_fd, sub.offset, sub.len);
- mClientHeap.clear();
+ mSize = 0;
}
#endif
}
@@ -157,10 +168,7 @@ MemoryHeapPmem::~MemoryHeapPmem()
sp<IMemory> MemoryHeapPmem::mapMemory(size_t offset, size_t size)
{
- sp<SubRegionMemory> memory;
- if (heapID() > 0)
- memory = new SubRegionMemory(this, offset, size);
-
+ sp<MemoryPmem> memory = createMemory(offset, size);
if (memory != 0) {
Mutex::Autolock _l(mLock);
mAllocations.add(memory);
@@ -168,6 +176,15 @@ sp<IMemory> MemoryHeapPmem::mapMemory(size_t offset, size_t size)
return memory;
}
+sp<MemoryHeapPmem::MemoryPmem> MemoryHeapPmem::createMemory(
+ size_t offset, size_t size)
+{
+ sp<SubRegionMemory> memory;
+ if (heapID() > 0)
+ memory = new SubRegionMemory(this, offset, size);
+ return memory;
+}
+
status_t MemoryHeapPmem::slap()
{
#if HAVE_ANDROID_OS
@@ -206,21 +223,26 @@ status_t MemoryHeapPmem::unslap()
void MemoryHeapPmem::revoke()
{
- Vector< wp<SubRegionMemory> > allocations;
+ SortedVector< wp<MemoryPmem> > allocations;
{ // scope for lock
Mutex::Autolock _l(mLock);
allocations = mAllocations;
- mAllocations.clear();
}
ssize_t count = allocations.size();
for (ssize_t i=0 ; i<count ; i++) {
- sp<SubRegionMemory> memory(allocations[i].promote());
+ sp<MemoryPmem> memory(allocations[i].promote());
if (memory != 0)
memory->revoke();
}
}
+void MemoryHeapPmem::remove(const wp<MemoryPmem>& memory)
+{
+ Mutex::Autolock _l(mLock);
+ mAllocations.remove(memory);
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index a5fe9fb..5a09fb4 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -164,7 +164,11 @@ void Res_png_9patch::fileToDevice()
size_t Res_png_9patch::serializedSize()
{
- return sizeof(Res_png_9patch)
+ // The size of this struct is 32 bytes on the 32-bit target system
+ // 4 * int8_t
+ // 4 * int32_t
+ // 3 * pointer
+ return 32
+ numXDivs * sizeof(int32_t)
+ numYDivs * sizeof(int32_t)
+ numColors * sizeof(uint32_t);
@@ -180,8 +184,10 @@ void* Res_png_9patch::serialize()
void Res_png_9patch::serialize(void * outData)
{
char* data = (char*) outData;
- memmove(data, this, sizeof(Res_png_9patch));
- data += sizeof(Res_png_9patch);
+ memmove(data, &wasDeserialized, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors
+ memmove(data + 12, &paddingLeft, 16); // copy paddingXXXX
+ data += 32;
+
memmove(data, this->xDivs, numXDivs * sizeof(int32_t));
data += numXDivs * sizeof(int32_t);
memmove(data, this->yDivs, numYDivs * sizeof(int32_t));
@@ -189,27 +195,32 @@ void Res_png_9patch::serialize(void * outData)
memmove(data, this->colors, numColors * sizeof(uint32_t));
}
-Res_png_9patch* Res_png_9patch::deserialize(const void* inData)
-{
- deserialize(inData, (Res_png_9patch*) inData);
- return (Res_png_9patch*) inData;
-}
-
-void Res_png_9patch::deserialize(const void* inData, Res_png_9patch* outData) {
- Res_png_9patch* patch = (Res_png_9patch*) inData;
+static void deserializeInternal(const void* inData, Res_png_9patch* outData) {
+ char* patch = (char*) inData;
if (inData != outData) {
- memcpy(outData, inData, patch->serializedSize());
+ memmove(&outData->wasDeserialized, patch, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors
+ memmove(&outData->paddingLeft, patch + 12, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors
}
outData->wasDeserialized = true;
char* data = (char*)outData;
data += sizeof(Res_png_9patch);
outData->xDivs = (int32_t*) data;
- data += patch->numXDivs * sizeof(int32_t);
+ data += outData->numXDivs * sizeof(int32_t);
outData->yDivs = (int32_t*) data;
- data += patch->numYDivs * sizeof(int32_t);
+ data += outData->numYDivs * sizeof(int32_t);
outData->colors = (uint32_t*) data;
}
+Res_png_9patch* Res_png_9patch::deserialize(const void* inData)
+{
+ if (sizeof(void*) != sizeof(int32_t)) {
+ LOGE("Cannot deserialize on non 32-bit system\n");
+ return NULL;
+ }
+ deserializeInternal(inData, (Res_png_9patch*) inData);
+ return (Res_png_9patch*) inData;
+}
+
// --------------------------------------------------------------------
// --------------------------------------------------------------------
// --------------------------------------------------------------------
@@ -3863,7 +3874,7 @@ void ResTable::print() const
}
for (size_t configIndex=0; configIndex<NTC; configIndex++) {
const ResTable_type* type = typeConfigs->configs[configIndex];
- if ((((int)type)&0x3) != 0) {
+ if ((((uint64_t)type)&0x3) != 0) {
printf(" NON-INTEGER ResTable_type ADDRESS: %p\n", type);
continue;
}
diff --git a/libs/utils/futex_synchro.c b/libs/utils/futex_synchro.c
index c13760d..ba19520 100644
--- a/libs/utils/futex_synchro.c
+++ b/libs/utils/futex_synchro.c
@@ -25,8 +25,8 @@
#include <private/utils/futex_synchro.h>
-// This futex glue code is need on desktop linux, but is part of klibc on ARM
-#if !defined(__arm__)
+// This futex glue code is need on desktop linux, but is already part of bionic.
+#if !defined(HAVE_FUTEX_WRAPPERS)
#include <sys/syscall.h>
typedef unsigned int u32;
@@ -76,7 +76,7 @@ int __atomic_cmpxchg(int old, int _new, volatile int *ptr);
int __atomic_swap(int _new, volatile int *ptr);
int __atomic_dec(volatile int *ptr);
-#endif // !defined(__arm__)
+#endif // !defined(HAVE_FUTEX_WRAPPERS)
// lock states