diff options
Diffstat (limited to 'libs')
67 files changed, 4182 insertions, 4217 deletions
diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/libs/audioflinger/A2dpAudioInterface.cpp index 351815b..747d0e4 100644 --- a/libs/audioflinger/A2dpAudioInterface.cpp +++ b/libs/audioflinger/A2dpAudioInterface.cpp @@ -185,7 +185,9 @@ String8 A2dpAudioInterface::getParameters(const String8& keys) String8 keyValuePairs = a2dpParam.toString(); if (param.size()) { - keyValuePairs += ";"; + if (keyValuePairs != "") { + keyValuePairs += ";"; + } keyValuePairs += mHardwareInterface->getParameters(param.toString()); } @@ -455,4 +457,10 @@ status_t A2dpAudioInterface::A2dpAudioStreamOut::dump(int fd, const Vector<Strin return NO_ERROR; } +status_t A2dpAudioInterface::A2dpAudioStreamOut::getRenderPosition(uint32_t *driverFrames) +{ + //TODO: enable when supported by driver + return INVALID_OPERATION; +} + }; // namespace android diff --git a/libs/audioflinger/A2dpAudioInterface.h b/libs/audioflinger/A2dpAudioInterface.h index 530e432..48154f9 100644 --- a/libs/audioflinger/A2dpAudioInterface.h +++ b/libs/audioflinger/A2dpAudioInterface.h @@ -93,6 +93,7 @@ private: virtual status_t dump(int fd, const Vector<String16>& args); virtual status_t setParameters(const String8& keyValuePairs); virtual String8 getParameters(const String8& keys); + virtual status_t getRenderPosition(uint32_t *dspFrames); private: friend class A2dpAudioInterface; diff --git a/libs/audioflinger/Android.mk b/libs/audioflinger/Android.mk index f5c03bb..870c0b8 100644 --- a/libs/audioflinger/Android.mk +++ b/libs/audioflinger/Android.mk @@ -24,7 +24,7 @@ endif LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils \ - libbinder \ + libbinder \ libmedia \ libhardware_legacy @@ -47,7 +47,7 @@ include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ - AudioPolicyManagerGeneric.cpp + AudioPolicyManagerBase.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ @@ -60,7 +60,7 @@ else LOCAL_SHARED_LIBRARIES += libdl endif -LOCAL_MODULE:= libaudiopolicygeneric +LOCAL_MODULE:= libaudiopolicybase ifeq ($(BOARD_HAVE_BLUETOOTH),true) LOCAL_CFLAGS += -DWITH_A2DP @@ -70,7 +70,7 @@ ifeq ($(AUDIO_POLICY_TEST),true) LOCAL_CFLAGS += -DAUDIO_POLICY_TEST endif -include $(BUILD_SHARED_LIBRARY) +include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) @@ -85,13 +85,12 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils \ - libbinder \ + libbinder \ libmedia \ - libhardware_legacy \ - libaudiopolicygeneric + libhardware_legacy ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true) - LOCAL_STATIC_LIBRARIES += libaudiointerface + LOCAL_STATIC_LIBRARIES += libaudiointerface libaudiopolicybase LOCAL_CFLAGS += -DGENERIC_AUDIO else LOCAL_SHARED_LIBRARIES += libaudio libaudiopolicy @@ -115,9 +114,17 @@ ifeq ($(AUDIO_POLICY_TEST),true) endif ifeq ($(TARGET_SIMULATOR),true) - ifeq ($(HOST_OS),linux) - LOCAL_LDLIBS += -lrt -lpthread - endif + ifeq ($(HOST_OS),linux) + LOCAL_LDLIBS += -lrt -lpthread + endif +endif + +ifeq ($(BOARD_USE_LVMX),true) + LOCAL_CFLAGS += -DLVMX + LOCAL_C_INCLUDES += vendor/nxp + LOCAL_STATIC_LIBRARIES += liblifevibes + LOCAL_SHARED_LIBRARIES += liblvmxservice +# LOCAL_SHARED_LIBRARIES += liblvmxipc endif include $(BUILD_SHARED_LIBRARY) diff --git a/libs/audioflinger/AudioDumpInterface.cpp b/libs/audioflinger/AudioDumpInterface.cpp index 858e5aa..a018b4c 100644 --- a/libs/audioflinger/AudioDumpInterface.cpp +++ b/libs/audioflinger/AudioDumpInterface.cpp @@ -379,6 +379,12 @@ void AudioStreamOutDump::Close() } } +status_t AudioStreamOutDump::getRenderPosition(uint32_t *dspFrames) +{ + if (mFinalStream != 0 ) return mFinalStream->getRenderPosition(dspFrames); + return INVALID_OPERATION; +} + // ---------------------------------------------------------------------------- AudioStreamInDump::AudioStreamInDump(AudioDumpInterface *interface, @@ -503,6 +509,12 @@ String8 AudioStreamInDump::getParameters(const String8& keys) return param.toString(); } +unsigned int AudioStreamInDump::getInputFramesLost() const +{ + if (mFinalStream != 0 ) return mFinalStream->getInputFramesLost(); + return 0; +} + status_t AudioStreamInDump::dump(int fd, const Vector<String16>& args) { if (mFinalStream != 0 ) return mFinalStream->dump(fd, args); diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h index 1136ce1..4c62b3e 100644 --- a/libs/audioflinger/AudioDumpInterface.h +++ b/libs/audioflinger/AudioDumpInterface.h @@ -56,8 +56,9 @@ public: void Close(void); AudioStreamOut* finalStream() { return mFinalStream; } uint32_t device() { return mDevice; } - int getId() { return mId; } + virtual status_t getRenderPosition(uint32_t *dspFrames); + private: AudioDumpInterface *mInterface; int mId; @@ -93,6 +94,7 @@ public: virtual status_t standby(); virtual status_t setParameters(const String8& keyValuePairs); virtual String8 getParameters(const String8& keys); + virtual unsigned int getInputFramesLost() const; virtual status_t dump(int fd, const Vector<String16>& args); void Close(void); AudioStreamIn* finalStream() { return mFinalStream; } diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp index ecfe1e0..7166c89 100644 --- a/libs/audioflinger/AudioFlinger.cpp +++ b/libs/audioflinger/AudioFlinger.cpp @@ -47,6 +47,10 @@ #include "A2dpAudioInterface.h" #endif +#ifdef LVMX +#include "lifevibes.h" +#endif + // ---------------------------------------------------------------------------- // the sim build doesn't have gettid @@ -68,6 +72,10 @@ static const float MAX_GAIN = 4096.0f; // 50 * ~20msecs = 1 second static const int8_t kMaxTrackRetries = 50; static const int8_t kMaxTrackStartupRetries = 50; +// allow less retry attempts on direct output thread. +// direct outputs can be a scarce resource in audio hardware and should +// be released as quickly as possible. +static const int8_t kMaxTrackRetriesDirect = 2; static const int kDumpLockRetries = 50; static const int kDumpLockSleep = 20000; @@ -132,6 +140,9 @@ AudioFlinger::AudioFlinger() } else { LOGE("Couldn't even initialize the stubbed audio hardware!"); } +#ifdef LVMX + LifeVibes::init(); +#endif } AudioFlinger::~AudioFlinger() @@ -411,6 +422,11 @@ status_t AudioFlinger::setMode(int mode) AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_HW_SET_MODE; status_t ret = mAudioHardware->setMode(mode); +#ifdef LVMX + if (NO_ERROR == ret) { + LifeVibes::setMode(mode); + } +#endif mHardwareStatus = AUDIO_HW_IDLE; return ret; } @@ -544,11 +560,11 @@ bool AudioFlinger::streamMute(int stream) const return mStreamTypes[stream].mute; } -bool AudioFlinger::isMusicActive() const +bool AudioFlinger::isStreamActive(int stream) const { Mutex::Autolock _l(mLock); for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) { - if (mPlaybackThreads.valueAt(i)->isMusicActive()) { + if (mPlaybackThreads.valueAt(i)->isStreamActive(stream)) { return true; } } @@ -566,11 +582,37 @@ status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs) return PERMISSION_DENIED; } +#ifdef LVMX + AudioParameter param = AudioParameter(keyValuePairs); + LifeVibes::setParameters(ioHandle,keyValuePairs); + String8 key = String8(AudioParameter::keyRouting); + int device; + if (NO_ERROR != param.getInt(key, device)) { + device = -1; + } + + key = String8(LifevibesTag); + String8 value; + int musicEnabled = -1; + if (NO_ERROR == param.get(key, value)) { + if (value == LifevibesEnable) { + musicEnabled = 1; + } else if (value == LifevibesDisable) { + musicEnabled = 0; + } + } +#endif + // ioHandle == 0 means the parameters are global to the audio hardware interface if (ioHandle == 0) { AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_SET_PARAMETER; result = mAudioHardware->setParameters(keyValuePairs); +#ifdef LVMX + if ((NO_ERROR == result) && (musicEnabled != -1)) { + LifeVibes::enableMusic((bool) musicEnabled); + } +#endif mHardwareStatus = AUDIO_HW_IDLE; return result; } @@ -586,7 +628,13 @@ status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs) } } if (thread != NULL) { - return thread->setParameters(keyValuePairs); + result = thread->setParameters(keyValuePairs); +#ifdef LVMX + if ((NO_ERROR == result) && (device != -1)) { + LifeVibes::setDevice(LifeVibes::threadIdToAudioOutputType(thread->id()), device); + } +#endif + return result; } return BAD_VALUE; } @@ -618,6 +666,21 @@ size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int cha return mAudioHardware->getInputBufferSize(sampleRate, format, channelCount); } +unsigned int AudioFlinger::getInputFramesLost(int ioHandle) +{ + if (ioHandle == 0) { + return 0; + } + + Mutex::Autolock _l(mLock); + + RecordThread *recordThread = checkRecordThread_l(ioHandle); + if (recordThread != NULL) { + return recordThread->getInputFramesLost(); + } + return 0; +} + status_t AudioFlinger::setVoiceVolume(float value) { // check calling permissions @@ -633,6 +696,20 @@ status_t AudioFlinger::setVoiceVolume(float value) return ret; } +status_t AudioFlinger::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output) +{ + status_t status; + + Mutex::Autolock _l(mLock); + + PlaybackThread *playbackThread = checkPlaybackThread_l(output); + if (playbackThread != NULL) { + return playbackThread->getRenderPosition(halFrames, dspFrames); + } + + return BAD_VALUE; +} + void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client) { @@ -1029,12 +1106,24 @@ uint32_t AudioFlinger::PlaybackThread::latency() const status_t AudioFlinger::PlaybackThread::setMasterVolume(float value) { +#ifdef LVMX + int audioOutputType = LifeVibes::getMixerType(mId, mType); + if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) { + LifeVibes::setMasterVolume(audioOutputType, value); + } +#endif mMasterVolume = value; return NO_ERROR; } status_t AudioFlinger::PlaybackThread::setMasterMute(bool muted) { +#ifdef LVMX + int audioOutputType = LifeVibes::getMixerType(mId, mType); + if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) { + LifeVibes::setMasterMute(audioOutputType, muted); + } +#endif mMasterMute = muted; return NO_ERROR; } @@ -1051,12 +1140,24 @@ bool AudioFlinger::PlaybackThread::masterMute() const status_t AudioFlinger::PlaybackThread::setStreamVolume(int stream, float value) { +#ifdef LVMX + int audioOutputType = LifeVibes::getMixerType(mId, mType); + if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) { + LifeVibes::setStreamVolume(audioOutputType, stream, value); + } +#endif mStreamTypes[stream].volume = value; return NO_ERROR; } status_t AudioFlinger::PlaybackThread::setStreamMute(int stream, bool muted) { +#ifdef LVMX + int audioOutputType = LifeVibes::getMixerType(mId, mType); + if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) { + LifeVibes::setStreamMute(audioOutputType, stream, muted); + } +#endif mStreamTypes[stream].mute = muted; return NO_ERROR; } @@ -1071,7 +1172,7 @@ bool AudioFlinger::PlaybackThread::streamMute(int stream) const return mStreamTypes[stream].mute; } -bool AudioFlinger::PlaybackThread::isMusicActive() const +bool AudioFlinger::PlaybackThread::isStreamActive(int stream) const { Mutex::Autolock _l(mLock); size_t count = mActiveTracks.size(); @@ -1079,7 +1180,7 @@ bool AudioFlinger::PlaybackThread::isMusicActive() const sp<Track> t = mActiveTracks[i].promote(); if (t == 0) continue; Track* const track = t.get(); - if (t->type() == AudioSystem::MUSIC) + if (t->type() == stream) return true; } return false; @@ -1166,6 +1267,19 @@ void AudioFlinger::PlaybackThread::readOutputParameters() memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t)); } +status_t AudioFlinger::PlaybackThread::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames) +{ + if (halFrames == 0 || dspFrames == 0) { + return BAD_VALUE; + } + if (mOutput == 0) { + return INVALID_OPERATION; + } + *halFrames = mBytesWritten/mOutput->frameSize(); + + return mOutput->getRenderPosition(dspFrames); +} + // ---------------------------------------------------------------------------- AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id) @@ -1290,8 +1404,15 @@ bool AudioFlinger::MixerThread::threadLoop() if (sleepTime == 0) { mLastWriteTime = systemTime(); mInWrite = true; + mBytesWritten += mixBufferSize; +#ifdef LVMX + int audioOutputType = LifeVibes::getMixerType(mId, mType); + if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) { + LifeVibes::process(audioOutputType, curBuf, mixBufferSize); + } +#endif int bytesWritten = (int)mOutput->write(curBuf, mixBufferSize); - if (bytesWritten > 0) mBytesWritten += bytesWritten; + if (bytesWritten < 0) mBytesWritten -= mixBufferSize; mNumWrites++; mInWrite = false; nsecs_t now = systemTime(); @@ -1333,6 +1454,29 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track uint32_t mixerStatus = MIXER_IDLE; // find out which tracks need to be processed size_t count = activeTracks.size(); + + float masterVolume = mMasterVolume; + bool masterMute = mMasterMute; + +#ifdef LVMX + bool tracksConnectedChanged = false; + bool stateChanged = false; + + int audioOutputType = LifeVibes::getMixerType(mId, mType); + if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) + { + int activeTypes = 0; + for (size_t i=0 ; i<count ; i++) { + sp<Track> t = activeTracks[i].promote(); + if (t == 0) continue; + Track* const track = t.get(); + int iTracktype=track->type(); + activeTypes |= 1<<track->type(); + } + LifeVibes::computeVolumes(audioOutputType, activeTypes, tracksConnectedChanged, stateChanged, masterVolume, masterMute); + } +#endif + for (size_t i=0 ; i<count ; i++) { sp<Track> t = activeTracks[i].promote(); if (t == 0) continue; @@ -1344,21 +1488,33 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track // for all its buffers to be filled before processing it mAudioMixer->setActiveTrack(track->name()); if (cblk->framesReady() && (track->isReady() || track->isStopped()) && - !track->isPaused()) + !track->isPaused() && !track->isTerminated()) { //LOGV("track %d u=%08x, s=%08x [OK] on thread %p", track->name(), cblk->user, cblk->server, this); // compute volume for this track int16_t left, right; - if (track->isMuted() || mMasterMute || track->isPausing() || + if (track->isMuted() || masterMute || track->isPausing() || mStreamTypes[track->type()].mute) { left = right = 0; if (track->isPausing()) { track->setPaused(); } } else { + // read original volumes with volume control float typeVolume = mStreamTypes[track->type()].volume; - float v = mMasterVolume * typeVolume; +#ifdef LVMX + bool streamMute=false; + // read the volume from the LivesVibes audio engine. + if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) + { + LifeVibes::getStreamVolumes(audioOutputType, track->type(), &typeVolume, &streamMute); + if (streamMute) { + typeVolume = 0; + } + } +#endif + float v = masterVolume * typeVolume; float v_clamped = v * cblk->volume[0]; if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN; left = int16_t(v_clamped); @@ -1384,7 +1540,13 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track // do not apply ramp param = AudioMixer::RAMP_VOLUME; } - +#ifdef LVMX + if ( tracksConnectedChanged || stateChanged ) + { + // only do the ramp when the volume is changed by the user / application + param = AudioMixer::VOLUME; + } +#endif mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left); mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right); mAudioMixer->setParameter( @@ -1636,6 +1798,9 @@ bool AudioFlinger::DirectOutputThread::threadLoop() uint32_t activeSleepTime = activeSleepTimeUs(); uint32_t idleSleepTime = idleSleepTimeUs(); uint32_t sleepTime = idleSleepTime; + // use shorter standby delay as on normal output to release + // hardware resources as soon as possible + nsecs_t standbyDelay = microseconds(activeSleepTime*2); while (!exitPending()) @@ -1652,6 +1817,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() mixBufferSize = mFrameCount*mFrameSize; activeSleepTime = activeSleepTimeUs(); idleSleepTime = idleSleepTimeUs(); + standbyDelay = microseconds(activeSleepTime*2); } // put audio hardware into standby after short delay @@ -1684,7 +1850,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() } } - standbyTime = systemTime() + kStandbyTimeInNsecs; + standbyTime = systemTime() + standbyDelay; sleepTime = idleSleepTime; continue; } @@ -1738,7 +1904,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() } // reset retry count - track->mRetryCount = kMaxTrackRetries; + track->mRetryCount = kMaxTrackRetriesDirect; activeTrack = t; mixerStatus = MIXER_TRACKS_READY; } else { @@ -1791,7 +1957,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() activeTrack->releaseBuffer(&buffer); } sleepTime = 0; - standbyTime = systemTime() + kStandbyTimeInNsecs; + standbyTime = systemTime() + standbyDelay; } else { if (sleepTime == 0) { if (mixerStatus == MIXER_TRACKS_ENABLED) { @@ -1812,8 +1978,9 @@ bool AudioFlinger::DirectOutputThread::threadLoop() if (sleepTime == 0) { mLastWriteTime = systemTime(); mInWrite = true; + mBytesWritten += mixBufferSize; int bytesWritten = (int)mOutput->write(mMixBuffer, mixBufferSize); - if (bytesWritten) mBytesWritten += bytesWritten; + if (bytesWritten < 0) mBytesWritten -= mixBufferSize; mNumWrites++; mInWrite = false; mStandby = false; @@ -2900,7 +3067,7 @@ void AudioFlinger::PlaybackThread::OutputTrack::clearBufferQueue() AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid) : RefBase(), mAudioFlinger(audioFlinger), - mMemoryDealer(new MemoryDealer(1024*1024)), + mMemoryDealer(new MemoryDealer(1024*1024, "AudioFlinger::Client")), mPid(pid) { // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer @@ -3203,7 +3370,10 @@ bool AudioFlinger::RecordThread::threadLoop() if (mBytesRead < 0) { LOGE("Error reading audio input"); if (mActiveTrack->mState == TrackBase::ACTIVE) { - sleep(1); + // Force input into standby so that it tries to + // recover at next read attempt + mInput->standby(); + usleep(5000); } mRsmpInIndex = mFrameCount; framesOut = 0; @@ -3385,7 +3555,10 @@ status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer* if (mBytesRead < 0) { LOGE("RecordThread::getNextBuffer() Error reading audio input"); if (mActiveTrack->mState == TrackBase::ACTIVE) { - sleep(1); + // Force input into standby so that it tries to + // recover at next read attempt + mInput->standby(); + usleep(5000); } buffer->raw = 0; buffer->frameCount = 0; @@ -3546,6 +3719,11 @@ void AudioFlinger::RecordThread::readInputParameters() mRsmpInIndex = mFrameCount; } +unsigned int AudioFlinger::RecordThread::getInputFramesLost() +{ + return mInput->getInputFramesLost(); +} + // ---------------------------------------------------------------------------- int AudioFlinger::openOutput(uint32_t *pDevices, @@ -3597,6 +3775,18 @@ int AudioFlinger::openOutput(uint32_t *pDevices, } else { thread = new MixerThread(this, output, ++mNextThreadId); LOGV("openOutput() created mixer output: ID %d thread %p", mNextThreadId, thread); + +#ifdef LVMX + unsigned bitsPerSample = + (format == AudioSystem::PCM_16_BIT) ? 16 : + ((format == AudioSystem::PCM_8_BIT) ? 8 : 0); + unsigned channelCount = (channels == AudioSystem::CHANNEL_OUT_STEREO) ? 2 : 1; + int audioOutputType = LifeVibes::threadIdToAudioOutputType(thread->id()); + + LifeVibes::init_aot(audioOutputType, samplingRate, bitsPerSample, channelCount); + LifeVibes::setDevice(audioOutputType, *pDevices); +#endif + } mPlaybackThreads.add(mNextThreadId, thread); diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h index 12c90eb..739ec33 100644 --- a/libs/audioflinger/AudioFlinger.h +++ b/libs/audioflinger/AudioFlinger.h @@ -100,7 +100,7 @@ public: virtual status_t setMicMute(bool state); virtual bool getMicMute() const; - virtual bool isMusicActive() const; + virtual bool isStreamActive(int stream) const; virtual status_t setParameters(int ioHandle, const String8& keyValuePairs); virtual String8 getParameters(int ioHandle, const String8& keys); @@ -108,6 +108,7 @@ public: virtual void registerClient(const sp<IAudioFlingerClient>& client); virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount); + virtual unsigned int getInputFramesLost(int ioHandle); virtual int openOutput(uint32_t *pDevices, uint32_t *pSamplingRate, @@ -136,6 +137,8 @@ public: virtual status_t setVoiceVolume(float volume); + virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output); + // IBinder::DeathRecipient virtual void binderDied(const wp<IBinder>& who); @@ -506,7 +509,7 @@ private: virtual float streamVolume(int stream) const; virtual bool streamMute(int stream) const; - bool isMusicActive() const; + bool isStreamActive(int stream) const; sp<Track> createTrack_l( const sp<AudioFlinger::Client>& client, @@ -526,6 +529,7 @@ private: bool isSuspended() { return (mSuspended != 0); } virtual String8 getParameters(const String8& keys); virtual void audioConfigChanged(int event, int param = 0); + virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames); struct stream_type_t { stream_type_t() @@ -742,6 +746,7 @@ private: virtual String8 getParameters(const String8& keys); virtual void audioConfigChanged(int event, int param = 0); void readInputParameters(); + virtual unsigned int getInputFramesLost(); private: RecordThread(); diff --git a/libs/audioflinger/AudioHardwareGeneric.cpp b/libs/audioflinger/AudioHardwareGeneric.cpp index 57874f3..d63c031 100644 --- a/libs/audioflinger/AudioHardwareGeneric.cpp +++ b/libs/audioflinger/AudioHardwareGeneric.cpp @@ -298,6 +298,11 @@ String8 AudioStreamOutGeneric::getParameters(const String8& keys) return param.toString(); } +status_t AudioStreamOutGeneric::getRenderPosition(uint32_t *dspFrames) +{ + return INVALID_OPERATION; +} + // ---------------------------------------------------------------------------- // record functions @@ -310,9 +315,8 @@ status_t AudioStreamInGeneric::set( uint32_t *pRate, AudioSystem::audio_in_acoustics acoustics) { - // FIXME: remove logging if (pFormat == 0 || pChannels == 0 || pRate == 0) return BAD_VALUE; - LOGD("AudioStreamInGeneric::set(%p, %d, %d, %d, %u)", hw, fd, *pFormat, *pChannels, *pRate); + LOGV("AudioStreamInGeneric::set(%p, %d, %d, %d, %u)", hw, fd, *pFormat, *pChannels, *pRate); // check values if ((*pFormat != format()) || (*pChannels != channels()) || @@ -332,14 +336,10 @@ status_t AudioStreamInGeneric::set( AudioStreamInGeneric::~AudioStreamInGeneric() { - // FIXME: remove logging - LOGD("AudioStreamInGeneric destructor"); } ssize_t AudioStreamInGeneric::read(void* buffer, ssize_t bytes) { - // FIXME: remove logging - LOGD("AudioStreamInGeneric::read(%p, %d) from fd %d", buffer, (int)bytes, mFd); AutoMutex lock(mLock); if (mFd < 0) { LOGE("Attempt to read from unopened device"); diff --git a/libs/audioflinger/AudioHardwareGeneric.h b/libs/audioflinger/AudioHardwareGeneric.h index 42da413..aa4e78d 100644 --- a/libs/audioflinger/AudioHardwareGeneric.h +++ b/libs/audioflinger/AudioHardwareGeneric.h @@ -55,6 +55,7 @@ public: virtual status_t dump(int fd, const Vector<String16>& args); virtual status_t setParameters(const String8& keyValuePairs); virtual String8 getParameters(const String8& keys); + virtual status_t getRenderPosition(uint32_t *dspFrames); private: AudioHardwareGeneric *mAudioHardware; @@ -87,6 +88,7 @@ public: virtual status_t standby() { return NO_ERROR; } virtual status_t setParameters(const String8& keyValuePairs); virtual String8 getParameters(const String8& keys); + virtual unsigned int getInputFramesLost() const { return 0; } private: AudioHardwareGeneric *mAudioHardware; diff --git a/libs/audioflinger/AudioHardwareStub.cpp b/libs/audioflinger/AudioHardwareStub.cpp index ae391ee..d481150 100644 --- a/libs/audioflinger/AudioHardwareStub.cpp +++ b/libs/audioflinger/AudioHardwareStub.cpp @@ -158,10 +158,15 @@ String8 AudioStreamOutStub::getParameters(const String8& keys) return param.toString(); } +status_t AudioStreamOutStub::getRenderPosition(uint32_t *dspFrames) +{ + return INVALID_OPERATION; +} + // ---------------------------------------------------------------------------- status_t AudioStreamInStub::set(int *pFormat, uint32_t *pChannels, uint32_t *pRate, - AudioSystem::audio_in_acoustics acoustics) + AudioSystem::audio_in_acoustics acoustics) { return NO_ERROR; } diff --git a/libs/audioflinger/AudioHardwareStub.h b/libs/audioflinger/AudioHardwareStub.h index 583f852..06a29de 100644 --- a/libs/audioflinger/AudioHardwareStub.h +++ b/libs/audioflinger/AudioHardwareStub.h @@ -41,6 +41,7 @@ public: virtual status_t dump(int fd, const Vector<String16>& args); virtual status_t setParameters(const String8& keyValuePairs) { return NO_ERROR;} virtual String8 getParameters(const String8& keys); + virtual status_t getRenderPosition(uint32_t *dspFrames); }; class AudioStreamInStub : public AudioStreamIn { @@ -56,6 +57,7 @@ public: virtual status_t standby() { return NO_ERROR; } virtual status_t setParameters(const String8& keyValuePairs) { return NO_ERROR;} virtual String8 getParameters(const String8& keys); + virtual unsigned int getInputFramesLost() const { return 0; } }; class AudioHardwareStub : public AudioHardwareBase diff --git a/libs/audioflinger/AudioPolicyManagerBase.cpp b/libs/audioflinger/AudioPolicyManagerBase.cpp new file mode 100644 index 0000000..c8b3f48 --- /dev/null +++ b/libs/audioflinger/AudioPolicyManagerBase.cpp @@ -0,0 +1,1972 @@ +/* + * Copyright (C) 2009 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 "AudioPolicyManagerBase" +//#define LOG_NDEBUG 0 +#include <utils/Log.h> +#include <hardware_legacy/AudioPolicyManagerBase.h> +#include <media/mediarecorder.h> + +namespace android { + + +// ---------------------------------------------------------------------------- +// AudioPolicyInterface implementation +// ---------------------------------------------------------------------------- + + +status_t AudioPolicyManagerBase::setDeviceConnectionState(AudioSystem::audio_devices device, + AudioSystem::device_connection_state state, + const char *device_address) +{ + + LOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address); + + // connect/disconnect only 1 device at a time + if (AudioSystem::popCount(device) != 1) return BAD_VALUE; + + if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) { + LOGE("setDeviceConnectionState() invalid address: %s", device_address); + return BAD_VALUE; + } + + // handle output devices + if (AudioSystem::isOutputDevice(device)) { + +#ifndef WITH_A2DP + if (AudioSystem::isA2dpDevice(device)) { + LOGE("setDeviceConnectionState() invalid device: %x", device); + return BAD_VALUE; + } +#endif + + switch (state) + { + // handle output device connection + case AudioSystem::DEVICE_STATE_AVAILABLE: + if (mAvailableOutputDevices & device) { + LOGW("setDeviceConnectionState() device already connected: %x", device); + return INVALID_OPERATION; + } + LOGV("setDeviceConnectionState() connecting device %x", device); + + // register new device as available + mAvailableOutputDevices |= device; + +#ifdef WITH_A2DP + // handle A2DP device connection + if (AudioSystem::isA2dpDevice(device)) { + status_t status = handleA2dpConnection(device, device_address); + if (status != NO_ERROR) { + mAvailableOutputDevices &= ~device; + return status; + } + } else +#endif + { + if (AudioSystem::isBluetoothScoDevice(device)) { + LOGV("setDeviceConnectionState() BT SCO device, address %s", device_address); + // keep track of SCO device address + mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN); +#ifdef WITH_A2DP + if (mA2dpOutput != 0 && + mPhoneState != AudioSystem::MODE_NORMAL) { + mpClientInterface->suspendOutput(mA2dpOutput); + } +#endif + } + } + break; + // handle output device disconnection + case AudioSystem::DEVICE_STATE_UNAVAILABLE: { + if (!(mAvailableOutputDevices & device)) { + LOGW("setDeviceConnectionState() device not connected: %x", device); + return INVALID_OPERATION; + } + + + LOGV("setDeviceConnectionState() disconnecting device %x", device); + // remove device from available output devices + mAvailableOutputDevices &= ~device; + +#ifdef WITH_A2DP + // handle A2DP device disconnection + if (AudioSystem::isA2dpDevice(device)) { + status_t status = handleA2dpDisconnection(device, device_address); + if (status != NO_ERROR) { + mAvailableOutputDevices |= device; + return status; + } + } else +#endif + { + if (AudioSystem::isBluetoothScoDevice(device)) { + mScoDeviceAddress = ""; +#ifdef WITH_A2DP + if (mA2dpOutput != 0 && + mPhoneState != AudioSystem::MODE_NORMAL) { + mpClientInterface->restoreOutput(mA2dpOutput); + } +#endif + } + } + } break; + + default: + LOGE("setDeviceConnectionState() invalid state: %x", state); + return BAD_VALUE; + } + + // request routing change if necessary + uint32_t newDevice = getNewDevice(mHardwareOutput, false); +#ifdef WITH_A2DP + checkOutputForAllStrategies(newDevice); + // A2DP outputs must be closed after checkOutputForAllStrategies() is executed + if (state == AudioSystem::DEVICE_STATE_UNAVAILABLE && AudioSystem::isA2dpDevice(device)) { + closeA2dpOutputs(); + } +#endif + updateDeviceForStrategy(); + setOutputDevice(mHardwareOutput, newDevice); + + if (device == AudioSystem::DEVICE_OUT_WIRED_HEADSET) { + device = AudioSystem::DEVICE_IN_WIRED_HEADSET; + } else if (device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO || + device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET || + device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT) { + device = AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET; + } else { + return NO_ERROR; + } + } + // handle input devices + if (AudioSystem::isInputDevice(device)) { + + switch (state) + { + // handle input device connection + case AudioSystem::DEVICE_STATE_AVAILABLE: { + if (mAvailableInputDevices & device) { + LOGW("setDeviceConnectionState() device already connected: %d", device); + return INVALID_OPERATION; + } + mAvailableInputDevices |= device; + } + break; + + // handle input device disconnection + case AudioSystem::DEVICE_STATE_UNAVAILABLE: { + if (!(mAvailableInputDevices & device)) { + LOGW("setDeviceConnectionState() device not connected: %d", device); + return INVALID_OPERATION; + } + mAvailableInputDevices &= ~device; + } break; + + default: + LOGE("setDeviceConnectionState() invalid state: %x", state); + return BAD_VALUE; + } + + audio_io_handle_t activeInput = getActiveInput(); + if (activeInput != 0) { + AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput); + uint32_t newDevice = getDeviceForInputSource(inputDesc->mInputSource); + if (newDevice != inputDesc->mDevice) { + LOGV("setDeviceConnectionState() changing device from %x to %x for input %d", + inputDesc->mDevice, newDevice, activeInput); + inputDesc->mDevice = newDevice; + AudioParameter param = AudioParameter(); + param.addInt(String8(AudioParameter::keyRouting), (int)newDevice); + mpClientInterface->setParameters(activeInput, param.toString()); + } + } + + return NO_ERROR; + } + + LOGW("setDeviceConnectionState() invalid device: %x", device); + return BAD_VALUE; +} + +AudioSystem::device_connection_state AudioPolicyManagerBase::getDeviceConnectionState(AudioSystem::audio_devices device, + const char *device_address) +{ + AudioSystem::device_connection_state state = AudioSystem::DEVICE_STATE_UNAVAILABLE; + String8 address = String8(device_address); + if (AudioSystem::isOutputDevice(device)) { + if (device & mAvailableOutputDevices) { +#ifdef WITH_A2DP + if (AudioSystem::isA2dpDevice(device) && + address != "" && mA2dpDeviceAddress != address) { + return state; + } +#endif + if (AudioSystem::isBluetoothScoDevice(device) && + address != "" && mScoDeviceAddress != address) { + return state; + } + state = AudioSystem::DEVICE_STATE_AVAILABLE; + } + } else if (AudioSystem::isInputDevice(device)) { + if (device & mAvailableInputDevices) { + state = AudioSystem::DEVICE_STATE_AVAILABLE; + } + } + + return state; +} + +void AudioPolicyManagerBase::setPhoneState(int state) +{ + LOGV("setPhoneState() state %d", state); + uint32_t newDevice = 0; + if (state < 0 || state >= AudioSystem::NUM_MODES) { + LOGW("setPhoneState() invalid state %d", state); + return; + } + + if (state == mPhoneState ) { + LOGW("setPhoneState() setting same state %d", state); + return; + } + + // if leaving call state, handle special case of active streams + // pertaining to sonification strategy see handleIncallSonification() + if (mPhoneState == AudioSystem::MODE_IN_CALL) { + LOGV("setPhoneState() in call state management: new state is %d", state); + for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { + handleIncallSonification(stream, false, true); + } + } + + // store previous phone state for management of sonification strategy below + int oldState = mPhoneState; + mPhoneState = state; + bool force = false; + + // are we entering or starting a call + if ((oldState != AudioSystem::MODE_IN_CALL) && (state == AudioSystem::MODE_IN_CALL)) { + LOGV(" Entering call in setPhoneState()"); + // force routing command to audio hardware when starting a call + // even if no device change is needed + force = true; + } else if ((oldState == AudioSystem::MODE_IN_CALL) && (state != AudioSystem::MODE_IN_CALL)) { + LOGV(" Exiting call in setPhoneState()"); + // force routing command to audio hardware when exiting a call + // even if no device change is needed + force = true; + } + + // check for device and output changes triggered by new phone state + newDevice = getNewDevice(mHardwareOutput, false); +#ifdef WITH_A2DP + checkOutputForAllStrategies(newDevice); + // suspend A2DP output if a SCO device is present. + if (mA2dpOutput != 0 && mScoDeviceAddress != "") { + if (oldState == AudioSystem::MODE_NORMAL) { + mpClientInterface->suspendOutput(mA2dpOutput); + } else if (state == AudioSystem::MODE_NORMAL) { + mpClientInterface->restoreOutput(mA2dpOutput); + } + } +#endif + updateDeviceForStrategy(); + + AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mHardwareOutput); + + // force routing command to audio hardware when ending call + // even if no device change is needed + if (oldState == AudioSystem::MODE_IN_CALL && newDevice == 0) { + newDevice = hwOutputDesc->device(); + } + + // when changing from ring tone to in call mode, mute the ringing tone + // immediately and delay the route change to avoid sending the ring tone + // tail into the earpiece or headset. + int delayMs = 0; + if (state == AudioSystem::MODE_IN_CALL && oldState == AudioSystem::MODE_RINGTONE) { + // delay the device change command by twice the output latency to have some margin + // and be sure that audio buffers not yet affected by the mute are out when + // we actually apply the route change + delayMs = hwOutputDesc->mLatency*2; + setStreamMute(AudioSystem::RING, true, mHardwareOutput); + } + + // change routing is necessary + setOutputDevice(mHardwareOutput, newDevice, force, delayMs); + + // if entering in call state, handle special case of active streams + // pertaining to sonification strategy see handleIncallSonification() + if (state == AudioSystem::MODE_IN_CALL) { + LOGV("setPhoneState() in call state management: new state is %d", state); + // unmute the ringing tone after a sufficient delay if it was muted before + // setting output device above + if (oldState == AudioSystem::MODE_RINGTONE) { + setStreamMute(AudioSystem::RING, false, mHardwareOutput, MUTE_TIME_MS); + } + for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { + handleIncallSonification(stream, true, true); + } + } + + // Flag that ringtone volume must be limited to music volume until we exit MODE_RINGTONE + if (state == AudioSystem::MODE_RINGTONE && + (hwOutputDesc->mRefCount[AudioSystem::MUSIC] || + (systemTime() - mMusicStopTime) < seconds(SONIFICATION_HEADSET_MUSIC_DELAY))) { + mLimitRingtoneVolume = true; + } else { + mLimitRingtoneVolume = false; + } +} + +void AudioPolicyManagerBase::setRingerMode(uint32_t mode, uint32_t mask) +{ + LOGV("setRingerMode() mode %x, mask %x", mode, mask); + + mRingerMode = mode; +} + +void AudioPolicyManagerBase::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) +{ + LOGV("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mPhoneState); + + bool forceVolumeReeval = false; + switch(usage) { + case AudioSystem::FOR_COMMUNICATION: + if (config != AudioSystem::FORCE_SPEAKER && config != AudioSystem::FORCE_BT_SCO && + config != AudioSystem::FORCE_NONE) { + LOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config); + return; + } + mForceUse[usage] = config; + break; + case AudioSystem::FOR_MEDIA: + if (config != AudioSystem::FORCE_HEADPHONES && config != AudioSystem::FORCE_BT_A2DP && + config != AudioSystem::FORCE_WIRED_ACCESSORY && config != AudioSystem::FORCE_NONE) { + LOGW("setForceUse() invalid config %d for FOR_MEDIA", config); + return; + } + mForceUse[usage] = config; + break; + case AudioSystem::FOR_RECORD: + if (config != AudioSystem::FORCE_BT_SCO && config != AudioSystem::FORCE_WIRED_ACCESSORY && + config != AudioSystem::FORCE_NONE) { + LOGW("setForceUse() invalid config %d for FOR_RECORD", config); + return; + } + mForceUse[usage] = config; + break; + case AudioSystem::FOR_DOCK: + if (config != AudioSystem::FORCE_NONE && config != AudioSystem::FORCE_BT_CAR_DOCK && + config != AudioSystem::FORCE_BT_DESK_DOCK && config != AudioSystem::FORCE_WIRED_ACCESSORY) { + LOGW("setForceUse() invalid config %d for FOR_DOCK", config); + } + forceVolumeReeval = true; + mForceUse[usage] = config; + break; + default: + LOGW("setForceUse() invalid usage %d", usage); + break; + } + + // check for device and output changes triggered by new phone state + uint32_t newDevice = getNewDevice(mHardwareOutput, false); +#ifdef WITH_A2DP + checkOutputForAllStrategies(newDevice); +#endif + updateDeviceForStrategy(); + setOutputDevice(mHardwareOutput, newDevice); + if (forceVolumeReeval) { + applyStreamVolumes(mHardwareOutput, newDevice); + } +} + +AudioSystem::forced_config AudioPolicyManagerBase::getForceUse(AudioSystem::force_use usage) +{ + return mForceUse[usage]; +} + +void AudioPolicyManagerBase::setSystemProperty(const char* property, const char* value) +{ + LOGV("setSystemProperty() property %s, value %s", property, value); + if (strcmp(property, "ro.camera.sound.forced") == 0) { + if (atoi(value)) { + LOGV("ENFORCED_AUDIBLE cannot be muted"); + mStreams[AudioSystem::ENFORCED_AUDIBLE].mCanBeMuted = false; + } else { + LOGV("ENFORCED_AUDIBLE can be muted"); + mStreams[AudioSystem::ENFORCED_AUDIBLE].mCanBeMuted = true; + } + } +} + +audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type stream, + uint32_t samplingRate, + uint32_t format, + uint32_t channels, + AudioSystem::output_flags flags) +{ + audio_io_handle_t output = 0; + uint32_t latency = 0; + routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream); + uint32_t device = getDeviceForStrategy(strategy); + LOGV("getOutput() stream %d, samplingRate %d, format %d, channels %x, flags %x", stream, samplingRate, format, channels, flags); + +#ifdef AUDIO_POLICY_TEST + if (mCurOutput != 0) { + LOGV("getOutput() test output mCurOutput %d, samplingRate %d, format %d, channels %x, mDirectOutput %d", + mCurOutput, mTestSamplingRate, mTestFormat, mTestChannels, mDirectOutput); + + if (mTestOutputs[mCurOutput] == 0) { + LOGV("getOutput() opening test output"); + AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(); + outputDesc->mDevice = mTestDevice; + outputDesc->mSamplingRate = mTestSamplingRate; + outputDesc->mFormat = mTestFormat; + outputDesc->mChannels = mTestChannels; + outputDesc->mLatency = mTestLatencyMs; + outputDesc->mFlags = (AudioSystem::output_flags)(mDirectOutput ? AudioSystem::OUTPUT_FLAG_DIRECT : 0); + outputDesc->mRefCount[stream] = 0; + mTestOutputs[mCurOutput] = mpClientInterface->openOutput(&outputDesc->mDevice, + &outputDesc->mSamplingRate, + &outputDesc->mFormat, + &outputDesc->mChannels, + &outputDesc->mLatency, + outputDesc->mFlags); + if (mTestOutputs[mCurOutput]) { + AudioParameter outputCmd = AudioParameter(); + outputCmd.addInt(String8("set_id"),mCurOutput); + mpClientInterface->setParameters(mTestOutputs[mCurOutput],outputCmd.toString()); + addOutput(mTestOutputs[mCurOutput], outputDesc); + } + } + return mTestOutputs[mCurOutput]; + } +#endif //AUDIO_POLICY_TEST + + // open a direct output if required by specified parameters + if (needsDirectOuput(stream, samplingRate, format, channels, flags, device)) { + + LOGV("getOutput() opening direct output device %x", device); + AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(); + outputDesc->mDevice = device; + outputDesc->mSamplingRate = samplingRate; + outputDesc->mFormat = format; + outputDesc->mChannels = channels; + outputDesc->mLatency = 0; + outputDesc->mFlags = (AudioSystem::output_flags)(flags | AudioSystem::OUTPUT_FLAG_DIRECT); + outputDesc->mRefCount[stream] = 0; + output = mpClientInterface->openOutput(&outputDesc->mDevice, + &outputDesc->mSamplingRate, + &outputDesc->mFormat, + &outputDesc->mChannels, + &outputDesc->mLatency, + outputDesc->mFlags); + + // only accept an output with the requeted parameters + if (output == 0 || + (samplingRate != 0 && samplingRate != outputDesc->mSamplingRate) || + (format != 0 && format != outputDesc->mFormat) || + (channels != 0 && channels != outputDesc->mChannels)) { + LOGV("getOutput() failed opening direct output: samplingRate %d, format %d, channels %d", + samplingRate, format, channels); + if (output != 0) { + mpClientInterface->closeOutput(output); + } + delete outputDesc; + return 0; + } + addOutput(output, outputDesc); + return output; + } + + if (channels != 0 && channels != AudioSystem::CHANNEL_OUT_MONO && + channels != AudioSystem::CHANNEL_OUT_STEREO) { + return 0; + } + // open a non direct output + + // get which output is suitable for the specified stream. The actual routing change will happen + // when startOutput() will be called + uint32_t a2dpDevice = device & AudioSystem::DEVICE_OUT_ALL_A2DP; + if (AudioSystem::popCount((AudioSystem::audio_devices)device) == 2) { +#ifdef WITH_A2DP + if (a2dpUsedForSonification() && a2dpDevice != 0) { + // if playing on 2 devices among which one is A2DP, use duplicated output + LOGV("getOutput() using duplicated output"); + LOGW_IF((mA2dpOutput == 0), "getOutput() A2DP device in multiple %x selected but A2DP output not opened", device); + output = mDuplicatedOutput; + } else +#endif + { + // if playing on 2 devices among which none is A2DP, use hardware output + output = mHardwareOutput; + } + LOGV("getOutput() using output %d for 2 devices %x", output, device); + } else { +#ifdef WITH_A2DP + if (a2dpDevice != 0) { + // if playing on A2DP device, use a2dp output + LOGW_IF((mA2dpOutput == 0), "getOutput() A2DP device %x selected but A2DP output not opened", device); + output = mA2dpOutput; + } else +#endif + { + // if playing on not A2DP device, use hardware output + output = mHardwareOutput; + } + } + + + LOGW_IF((output ==0), "getOutput() could not find output for stream %d, samplingRate %d, format %d, channels %x, flags %x", + stream, samplingRate, format, channels, flags); + + return output; +} + +status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream) +{ + LOGV("startOutput() output %d, stream %d", output, stream); + ssize_t index = mOutputs.indexOfKey(output); + if (index < 0) { + LOGW("startOutput() unknow output %d", output); + return BAD_VALUE; + } + + AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); + routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream); + +#ifdef WITH_A2DP + if (mA2dpOutput != 0 && !a2dpUsedForSonification() && strategy == STRATEGY_SONIFICATION) { + setStrategyMute(STRATEGY_MEDIA, true, mA2dpOutput); + } +#endif + + // incremenent usage count for this stream on the requested output: + // NOTE that the usage count is the same for duplicated output and hardware output which is + // necassary for a correct control of hardware output routing by startOutput() and stopOutput() + outputDesc->changeRefCount(stream, 1); + + setOutputDevice(output, getNewDevice(output)); + + // handle special case for sonification while in call + if (mPhoneState == AudioSystem::MODE_IN_CALL) { + handleIncallSonification(stream, true, false); + } + + // apply volume rules for current stream and device if necessary + checkAndSetVolume(stream, mStreams[stream].mIndexCur, output, outputDesc->device()); + + return NO_ERROR; +} + +status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream) +{ + LOGV("stopOutput() output %d, stream %d", output, stream); + ssize_t index = mOutputs.indexOfKey(output); + if (index < 0) { + LOGW("stopOutput() unknow output %d", output); + return BAD_VALUE; + } + + AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); + routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream); + + // handle special case for sonification while in call + if (mPhoneState == AudioSystem::MODE_IN_CALL) { + handleIncallSonification(stream, false, false); + } + + if (outputDesc->mRefCount[stream] > 0) { + // decrement usage count of this stream on the output + outputDesc->changeRefCount(stream, -1); + // store time at which the last music track was stopped - see computeVolume() + if (stream == AudioSystem::MUSIC) { + mMusicStopTime = systemTime(); + } + + setOutputDevice(output, getNewDevice(output)); + +#ifdef WITH_A2DP + if (mA2dpOutput != 0 && !a2dpUsedForSonification() && strategy == STRATEGY_SONIFICATION) { + setStrategyMute(STRATEGY_MEDIA, false, mA2dpOutput, mOutputs.valueFor(mHardwareOutput)->mLatency*2); + } +#endif + if (output != mHardwareOutput) { + setOutputDevice(mHardwareOutput, getNewDevice(mHardwareOutput), true); + } + return NO_ERROR; + } else { + LOGW("stopOutput() refcount is already 0 for output %d", output); + return INVALID_OPERATION; + } +} + +void AudioPolicyManagerBase::releaseOutput(audio_io_handle_t output) +{ + LOGV("releaseOutput() %d", output); + ssize_t index = mOutputs.indexOfKey(output); + if (index < 0) { + LOGW("releaseOutput() releasing unknown output %d", output); + return; + } + +#ifdef AUDIO_POLICY_TEST + int testIndex = testOutputIndex(output); + if (testIndex != 0) { + AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); + if (outputDesc->refCount() == 0) { + mpClientInterface->closeOutput(output); + delete mOutputs.valueAt(index); + mOutputs.removeItem(output); + mTestOutputs[testIndex] = 0; + } + return; + } +#endif //AUDIO_POLICY_TEST + + if (mOutputs.valueAt(index)->mFlags & AudioSystem::OUTPUT_FLAG_DIRECT) { + mpClientInterface->closeOutput(output); + delete mOutputs.valueAt(index); + mOutputs.removeItem(output); + } +} + +audio_io_handle_t AudioPolicyManagerBase::getInput(int inputSource, + uint32_t samplingRate, + uint32_t format, + uint32_t channels, + AudioSystem::audio_in_acoustics acoustics) +{ + audio_io_handle_t input = 0; + uint32_t device = getDeviceForInputSource(inputSource); + + LOGV("getInput() inputSource %d, samplingRate %d, format %d, channels %x, acoustics %x", inputSource, samplingRate, format, channels, acoustics); + + if (device == 0) { + return 0; + } + + // adapt channel selection to input source + switch(inputSource) { + case AUDIO_SOURCE_VOICE_UPLINK: + channels = AudioSystem::CHANNEL_IN_VOICE_UPLINK; + break; + case AUDIO_SOURCE_VOICE_DOWNLINK: + channels = AudioSystem::CHANNEL_IN_VOICE_DNLINK; + break; + case AUDIO_SOURCE_VOICE_CALL: + channels = (AudioSystem::CHANNEL_IN_VOICE_UPLINK | AudioSystem::CHANNEL_IN_VOICE_DNLINK); + break; + default: + break; + } + + AudioInputDescriptor *inputDesc = new AudioInputDescriptor(); + + inputDesc->mInputSource = inputSource; + inputDesc->mDevice = device; + inputDesc->mSamplingRate = samplingRate; + inputDesc->mFormat = format; + inputDesc->mChannels = channels; + inputDesc->mAcoustics = acoustics; + inputDesc->mRefCount = 0; + input = mpClientInterface->openInput(&inputDesc->mDevice, + &inputDesc->mSamplingRate, + &inputDesc->mFormat, + &inputDesc->mChannels, + inputDesc->mAcoustics); + + // only accept input with the exact requested set of parameters + if (input == 0 || + (samplingRate != inputDesc->mSamplingRate) || + (format != inputDesc->mFormat) || + (channels != inputDesc->mChannels)) { + LOGV("getInput() failed opening input: samplingRate %d, format %d, channels %d", + samplingRate, format, channels); + if (input != 0) { + mpClientInterface->closeInput(input); + } + delete inputDesc; + return 0; + } + mInputs.add(input, inputDesc); + return input; +} + +status_t AudioPolicyManagerBase::startInput(audio_io_handle_t input) +{ + LOGV("startInput() input %d", input); + ssize_t index = mInputs.indexOfKey(input); + if (index < 0) { + LOGW("startInput() unknow input %d", input); + return BAD_VALUE; + } + AudioInputDescriptor *inputDesc = mInputs.valueAt(index); + +#ifdef AUDIO_POLICY_TEST + if (mTestInput == 0) +#endif //AUDIO_POLICY_TEST + { + // refuse 2 active AudioRecord clients at the same time + if (getActiveInput() != 0) { + LOGW("startInput() input %d failed: other input already started", input); + return INVALID_OPERATION; + } + } + + AudioParameter param = AudioParameter(); + param.addInt(String8(AudioParameter::keyRouting), (int)inputDesc->mDevice); + + // use Voice Recognition mode or not for this input based on input source + int vr_enabled = inputDesc->mInputSource == AUDIO_SOURCE_VOICE_RECOGNITION ? 1 : 0; + param.addInt(String8("vr_mode"), vr_enabled); + LOGV("AudioPolicyManager::startInput(%d), setting vr_mode to %d", inputDesc->mInputSource, vr_enabled); + + mpClientInterface->setParameters(input, param.toString()); + + inputDesc->mRefCount = 1; + return NO_ERROR; +} + +status_t AudioPolicyManagerBase::stopInput(audio_io_handle_t input) +{ + LOGV("stopInput() input %d", input); + ssize_t index = mInputs.indexOfKey(input); + if (index < 0) { + LOGW("stopInput() unknow input %d", input); + return BAD_VALUE; + } + AudioInputDescriptor *inputDesc = mInputs.valueAt(index); + + if (inputDesc->mRefCount == 0) { + LOGW("stopInput() input %d already stopped", input); + return INVALID_OPERATION; + } else { + AudioParameter param = AudioParameter(); + param.addInt(String8(AudioParameter::keyRouting), 0); + mpClientInterface->setParameters(input, param.toString()); + inputDesc->mRefCount = 0; + return NO_ERROR; + } +} + +void AudioPolicyManagerBase::releaseInput(audio_io_handle_t input) +{ + LOGV("releaseInput() %d", input); + ssize_t index = mInputs.indexOfKey(input); + if (index < 0) { + LOGW("releaseInput() releasing unknown input %d", input); + return; + } + mpClientInterface->closeInput(input); + delete mInputs.valueAt(index); + mInputs.removeItem(input); + LOGV("releaseInput() exit"); +} + +void AudioPolicyManagerBase::initStreamVolume(AudioSystem::stream_type stream, + int indexMin, + int indexMax) +{ + LOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax); + if (indexMin < 0 || indexMin >= indexMax) { + LOGW("initStreamVolume() invalid index limits for stream %d, min %d, max %d", stream , indexMin, indexMax); + return; + } + mStreams[stream].mIndexMin = indexMin; + mStreams[stream].mIndexMax = indexMax; +} + +status_t AudioPolicyManagerBase::setStreamVolumeIndex(AudioSystem::stream_type stream, int index) +{ + + if ((index < mStreams[stream].mIndexMin) || (index > mStreams[stream].mIndexMax)) { + return BAD_VALUE; + } + + // Force max volume if stream cannot be muted + if (!mStreams[stream].mCanBeMuted) index = mStreams[stream].mIndexMax; + + LOGV("setStreamVolumeIndex() stream %d, index %d", stream, index); + mStreams[stream].mIndexCur = index; + + // compute and apply stream volume on all outputs according to connected device + status_t status = NO_ERROR; + for (size_t i = 0; i < mOutputs.size(); i++) { + status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt(i), mOutputs.valueAt(i)->device()); + if (volStatus != NO_ERROR) { + status = volStatus; + } + } + return status; +} + +status_t AudioPolicyManagerBase::getStreamVolumeIndex(AudioSystem::stream_type stream, int *index) +{ + if (index == 0) { + return BAD_VALUE; + } + LOGV("getStreamVolumeIndex() stream %d", stream); + *index = mStreams[stream].mIndexCur; + return NO_ERROR; +} + +status_t AudioPolicyManagerBase::dump(int fd) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + snprintf(buffer, SIZE, "\nAudioPolicyManager Dump: %p\n", this); + result.append(buffer); + snprintf(buffer, SIZE, " Hardware Output: %d\n", mHardwareOutput); + result.append(buffer); +#ifdef WITH_A2DP + snprintf(buffer, SIZE, " A2DP Output: %d\n", mA2dpOutput); + result.append(buffer); + snprintf(buffer, SIZE, " Duplicated Output: %d\n", mDuplicatedOutput); + result.append(buffer); + snprintf(buffer, SIZE, " A2DP device address: %s\n", mA2dpDeviceAddress.string()); + result.append(buffer); +#endif + snprintf(buffer, SIZE, " SCO device address: %s\n", mScoDeviceAddress.string()); + result.append(buffer); + snprintf(buffer, SIZE, " Output devices: %08x\n", mAvailableOutputDevices); + result.append(buffer); + snprintf(buffer, SIZE, " Input devices: %08x\n", mAvailableInputDevices); + result.append(buffer); + snprintf(buffer, SIZE, " Phone state: %d\n", mPhoneState); + result.append(buffer); + snprintf(buffer, SIZE, " Ringer mode: %d\n", mRingerMode); + result.append(buffer); + snprintf(buffer, SIZE, " Force use for communications %d\n", mForceUse[AudioSystem::FOR_COMMUNICATION]); + result.append(buffer); + snprintf(buffer, SIZE, " Force use for media %d\n", mForceUse[AudioSystem::FOR_MEDIA]); + result.append(buffer); + snprintf(buffer, SIZE, " Force use for record %d\n", mForceUse[AudioSystem::FOR_RECORD]); + result.append(buffer); + snprintf(buffer, SIZE, " Force use for dock %d\n", mForceUse[AudioSystem::FOR_DOCK]); + result.append(buffer); + write(fd, result.string(), result.size()); + + snprintf(buffer, SIZE, "\nOutputs dump:\n"); + write(fd, buffer, strlen(buffer)); + for (size_t i = 0; i < mOutputs.size(); i++) { + snprintf(buffer, SIZE, "- Output %d dump:\n", mOutputs.keyAt(i)); + write(fd, buffer, strlen(buffer)); + mOutputs.valueAt(i)->dump(fd); + } + + snprintf(buffer, SIZE, "\nInputs dump:\n"); + write(fd, buffer, strlen(buffer)); + for (size_t i = 0; i < mInputs.size(); i++) { + snprintf(buffer, SIZE, "- Input %d dump:\n", mInputs.keyAt(i)); + write(fd, buffer, strlen(buffer)); + mInputs.valueAt(i)->dump(fd); + } + + snprintf(buffer, SIZE, "\nStreams dump:\n"); + write(fd, buffer, strlen(buffer)); + snprintf(buffer, SIZE, " Stream Index Min Index Max Index Cur Can be muted\n"); + write(fd, buffer, strlen(buffer)); + for (size_t i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) { + snprintf(buffer, SIZE, " %02d", i); + mStreams[i].dump(buffer + 3, SIZE); + write(fd, buffer, strlen(buffer)); + } + + return NO_ERROR; +} + +// ---------------------------------------------------------------------------- +// AudioPolicyManagerBase +// ---------------------------------------------------------------------------- + +AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface) + : +#ifdef AUDIO_POLICY_TEST + Thread(false), +#endif //AUDIO_POLICY_TEST + mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0), mMusicStopTime(0), mLimitRingtoneVolume(false) +{ + mpClientInterface = clientInterface; + + for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) { + mForceUse[i] = AudioSystem::FORCE_NONE; + } + + // devices available by default are speaker, ear piece and microphone + mAvailableOutputDevices = AudioSystem::DEVICE_OUT_EARPIECE | + AudioSystem::DEVICE_OUT_SPEAKER; + mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC; + +#ifdef WITH_A2DP + mA2dpOutput = 0; + mDuplicatedOutput = 0; + mA2dpDeviceAddress = String8(""); +#endif + mScoDeviceAddress = String8(""); + + // open hardware output + AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(); + outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER; + mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice, + &outputDesc->mSamplingRate, + &outputDesc->mFormat, + &outputDesc->mChannels, + &outputDesc->mLatency, + outputDesc->mFlags); + + if (mHardwareOutput == 0) { + LOGE("Failed to initialize hardware output stream, samplingRate: %d, format %d, channels %d", + outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannels); + } else { + addOutput(mHardwareOutput, outputDesc); + setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER, true); + } + + updateDeviceForStrategy(); +#ifdef AUDIO_POLICY_TEST + AudioParameter outputCmd = AudioParameter(); + outputCmd.addInt(String8("set_id"), 0); + mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString()); + + mTestDevice = AudioSystem::DEVICE_OUT_SPEAKER; + mTestSamplingRate = 44100; + mTestFormat = AudioSystem::PCM_16_BIT; + mTestChannels = AudioSystem::CHANNEL_OUT_STEREO; + mTestLatencyMs = 0; + mCurOutput = 0; + mDirectOutput = false; + for (int i = 0; i < NUM_TEST_OUTPUTS; i++) { + mTestOutputs[i] = 0; + } + + const size_t SIZE = 256; + char buffer[SIZE]; + snprintf(buffer, SIZE, "AudioPolicyManagerTest"); + run(buffer, ANDROID_PRIORITY_AUDIO); +#endif //AUDIO_POLICY_TEST +} + +AudioPolicyManagerBase::~AudioPolicyManagerBase() +{ +#ifdef AUDIO_POLICY_TEST + exit(); +#endif //AUDIO_POLICY_TEST + for (size_t i = 0; i < mOutputs.size(); i++) { + mpClientInterface->closeOutput(mOutputs.keyAt(i)); + delete mOutputs.valueAt(i); + } + mOutputs.clear(); + for (size_t i = 0; i < mInputs.size(); i++) { + mpClientInterface->closeInput(mInputs.keyAt(i)); + delete mInputs.valueAt(i); + } + mInputs.clear(); +} + +#ifdef AUDIO_POLICY_TEST +bool AudioPolicyManagerBase::threadLoop() +{ + LOGV("entering threadLoop()"); + while (!exitPending()) + { + String8 command; + int valueInt; + String8 value; + + Mutex::Autolock _l(mLock); + mWaitWorkCV.waitRelative(mLock, milliseconds(50)); + + command = mpClientInterface->getParameters(0, String8("test_cmd_policy")); + AudioParameter param = AudioParameter(command); + + if (param.getInt(String8("test_cmd_policy"), valueInt) == NO_ERROR && + valueInt != 0) { + LOGV("Test command %s received", command.string()); + String8 target; + if (param.get(String8("target"), target) != NO_ERROR) { + target = "Manager"; + } + if (param.getInt(String8("test_cmd_policy_output"), valueInt) == NO_ERROR) { + param.remove(String8("test_cmd_policy_output")); + mCurOutput = valueInt; + } + if (param.get(String8("test_cmd_policy_direct"), value) == NO_ERROR) { + param.remove(String8("test_cmd_policy_direct")); + if (value == "false") { + mDirectOutput = false; + } else if (value == "true") { + mDirectOutput = true; + } + } + if (param.getInt(String8("test_cmd_policy_input"), valueInt) == NO_ERROR) { + param.remove(String8("test_cmd_policy_input")); + mTestInput = valueInt; + } + + if (param.get(String8("test_cmd_policy_format"), value) == NO_ERROR) { + param.remove(String8("test_cmd_policy_format")); + int format = AudioSystem::INVALID_FORMAT; + if (value == "PCM 16 bits") { + format = AudioSystem::PCM_16_BIT; + } else if (value == "PCM 8 bits") { + format = AudioSystem::PCM_8_BIT; + } else if (value == "Compressed MP3") { + format = AudioSystem::MP3; + } + if (format != AudioSystem::INVALID_FORMAT) { + if (target == "Manager") { + mTestFormat = format; + } else if (mTestOutputs[mCurOutput] != 0) { + AudioParameter outputParam = AudioParameter(); + outputParam.addInt(String8("format"), format); + mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString()); + } + } + } + if (param.get(String8("test_cmd_policy_channels"), value) == NO_ERROR) { + param.remove(String8("test_cmd_policy_channels")); + int channels = 0; + + if (value == "Channels Stereo") { + channels = AudioSystem::CHANNEL_OUT_STEREO; + } else if (value == "Channels Mono") { + channels = AudioSystem::CHANNEL_OUT_MONO; + } + if (channels != 0) { + if (target == "Manager") { + mTestChannels = channels; + } else if (mTestOutputs[mCurOutput] != 0) { + AudioParameter outputParam = AudioParameter(); + outputParam.addInt(String8("channels"), channels); + mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString()); + } + } + } + if (param.getInt(String8("test_cmd_policy_sampleRate"), valueInt) == NO_ERROR) { + param.remove(String8("test_cmd_policy_sampleRate")); + if (valueInt >= 0 && valueInt <= 96000) { + int samplingRate = valueInt; + if (target == "Manager") { + mTestSamplingRate = samplingRate; + } else if (mTestOutputs[mCurOutput] != 0) { + AudioParameter outputParam = AudioParameter(); + outputParam.addInt(String8("sampling_rate"), samplingRate); + mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString()); + } + } + } + + if (param.get(String8("test_cmd_policy_reopen"), value) == NO_ERROR) { + param.remove(String8("test_cmd_policy_reopen")); + + mpClientInterface->closeOutput(mHardwareOutput); + delete mOutputs.valueFor(mHardwareOutput); + mOutputs.removeItem(mHardwareOutput); + + AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(); + outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER; + mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice, + &outputDesc->mSamplingRate, + &outputDesc->mFormat, + &outputDesc->mChannels, + &outputDesc->mLatency, + outputDesc->mFlags); + if (mHardwareOutput == 0) { + LOGE("Failed to reopen hardware output stream, samplingRate: %d, format %d, channels %d", + outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannels); + } else { + AudioParameter outputCmd = AudioParameter(); + outputCmd.addInt(String8("set_id"), 0); + mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString()); + addOutput(mHardwareOutput, outputDesc); + } + } + + + mpClientInterface->setParameters(0, String8("test_cmd_policy=")); + } + } + return false; +} + +void AudioPolicyManagerBase::exit() +{ + { + AutoMutex _l(mLock); + requestExit(); + mWaitWorkCV.signal(); + } + requestExitAndWait(); +} + +int AudioPolicyManagerBase::testOutputIndex(audio_io_handle_t output) +{ + for (int i = 0; i < NUM_TEST_OUTPUTS; i++) { + if (output == mTestOutputs[i]) return i; + } + return 0; +} +#endif //AUDIO_POLICY_TEST + +// --- + +void AudioPolicyManagerBase::addOutput(audio_io_handle_t id, AudioOutputDescriptor *outputDesc) +{ + outputDesc->mId = id; + mOutputs.add(id, outputDesc); +} + + +#ifdef WITH_A2DP +status_t AudioPolicyManagerBase::handleA2dpConnection(AudioSystem::audio_devices device, + const char *device_address) +{ + // when an A2DP device is connected, open an A2DP and a duplicated output + LOGV("opening A2DP output for device %s", device_address); + AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(); + outputDesc->mDevice = device; + mA2dpOutput = mpClientInterface->openOutput(&outputDesc->mDevice, + &outputDesc->mSamplingRate, + &outputDesc->mFormat, + &outputDesc->mChannels, + &outputDesc->mLatency, + outputDesc->mFlags); + if (mA2dpOutput) { + // add A2DP output descriptor + addOutput(mA2dpOutput, outputDesc); + // set initial stream volume for A2DP device + applyStreamVolumes(mA2dpOutput, device); + if (a2dpUsedForSonification()) { + mDuplicatedOutput = mpClientInterface->openDuplicateOutput(mA2dpOutput, mHardwareOutput); + } + if (mDuplicatedOutput != 0 || + !a2dpUsedForSonification()) { + // If both A2DP and duplicated outputs are open, send device address to A2DP hardware + // interface + AudioParameter param; + param.add(String8("a2dp_sink_address"), String8(device_address)); + mpClientInterface->setParameters(mA2dpOutput, param.toString()); + mA2dpDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN); + + if (a2dpUsedForSonification()) { + // add duplicated output descriptor + AudioOutputDescriptor *dupOutputDesc = new AudioOutputDescriptor(); + dupOutputDesc->mOutput1 = mOutputs.valueFor(mHardwareOutput); + dupOutputDesc->mOutput2 = mOutputs.valueFor(mA2dpOutput); + dupOutputDesc->mSamplingRate = outputDesc->mSamplingRate; + dupOutputDesc->mFormat = outputDesc->mFormat; + dupOutputDesc->mChannels = outputDesc->mChannels; + dupOutputDesc->mLatency = outputDesc->mLatency; + addOutput(mDuplicatedOutput, dupOutputDesc); + applyStreamVolumes(mDuplicatedOutput, device); + } + } else { + LOGW("getOutput() could not open duplicated output for %d and %d", + mHardwareOutput, mA2dpOutput); + mpClientInterface->closeOutput(mA2dpOutput); + mOutputs.removeItem(mA2dpOutput); + mA2dpOutput = 0; + delete outputDesc; + return NO_INIT; + } + } else { + LOGW("setDeviceConnectionState() could not open A2DP output for device %x", device); + delete outputDesc; + return NO_INIT; + } + AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mHardwareOutput); + + if (mScoDeviceAddress != "") { + // It is normal to suspend twice if we are both in call, + // and have the hardware audio output routed to BT SCO + if (mPhoneState != AudioSystem::MODE_NORMAL) { + mpClientInterface->suspendOutput(mA2dpOutput); + } + if (AudioSystem::isBluetoothScoDevice((AudioSystem::audio_devices)hwOutputDesc->device())) { + mpClientInterface->suspendOutput(mA2dpOutput); + } + } + + if (!a2dpUsedForSonification()) { + // mute music on A2DP output if a notification or ringtone is playing + uint32_t refCount = hwOutputDesc->strategyRefCount(STRATEGY_SONIFICATION); + for (uint32_t i = 0; i < refCount; i++) { + setStrategyMute(STRATEGY_MEDIA, true, mA2dpOutput); + } + } + return NO_ERROR; +} + +status_t AudioPolicyManagerBase::handleA2dpDisconnection(AudioSystem::audio_devices device, + const char *device_address) +{ + if (mA2dpOutput == 0) { + LOGW("setDeviceConnectionState() disconnecting A2DP and no A2DP output!"); + return INVALID_OPERATION; + } + + if (mA2dpDeviceAddress != device_address) { + LOGW("setDeviceConnectionState() disconnecting unknow A2DP sink address %s", device_address); + return INVALID_OPERATION; + } + + // mute media strategy to avoid outputting sound on hardware output while music stream + // is switched from A2DP output and before music is paused by music application + setStrategyMute(STRATEGY_MEDIA, true, mHardwareOutput); + setStrategyMute(STRATEGY_MEDIA, false, mHardwareOutput, MUTE_TIME_MS); + + if (!a2dpUsedForSonification()) { + // unmute music on A2DP output if a notification or ringtone is playing + uint32_t refCount = mOutputs.valueFor(mHardwareOutput)->strategyRefCount(STRATEGY_SONIFICATION); + for (uint32_t i = 0; i < refCount; i++) { + setStrategyMute(STRATEGY_MEDIA, false, mA2dpOutput); + } + } + mA2dpDeviceAddress = ""; + return NO_ERROR; +} + +void AudioPolicyManagerBase::closeA2dpOutputs() +{ + LOGV("setDeviceConnectionState() closing A2DP and duplicated output!"); + + if (mDuplicatedOutput != 0) { + mpClientInterface->closeOutput(mDuplicatedOutput); + delete mOutputs.valueFor(mDuplicatedOutput); + mOutputs.removeItem(mDuplicatedOutput); + mDuplicatedOutput = 0; + } + if (mA2dpOutput != 0) { + AudioParameter param; + param.add(String8("closing"), String8("true")); + mpClientInterface->setParameters(mA2dpOutput, param.toString()); + mpClientInterface->closeOutput(mA2dpOutput); + delete mOutputs.valueFor(mA2dpOutput); + mOutputs.removeItem(mA2dpOutput); + mA2dpOutput = 0; + } +} + +void AudioPolicyManagerBase::checkOutputForStrategy(routing_strategy strategy, uint32_t &newDevice) +{ + uint32_t prevDevice = getDeviceForStrategy(strategy); + uint32_t curDevice = getDeviceForStrategy(strategy, false); + bool a2dpWasUsed = AudioSystem::isA2dpDevice((AudioSystem::audio_devices)(prevDevice & ~AudioSystem::DEVICE_OUT_SPEAKER)); + bool a2dpIsUsed = AudioSystem::isA2dpDevice((AudioSystem::audio_devices)(curDevice & ~AudioSystem::DEVICE_OUT_SPEAKER)); + AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mHardwareOutput); + AudioOutputDescriptor *a2dpOutputDesc; + + if (a2dpWasUsed && !a2dpIsUsed) { + bool dupUsed = a2dpUsedForSonification() && a2dpWasUsed && (AudioSystem::popCount(prevDevice) == 2); + + if (dupUsed) { + LOGV("checkOutputForStrategy() moving strategy %d to duplicated", strategy); + a2dpOutputDesc = mOutputs.valueFor(mDuplicatedOutput); + } else { + LOGV("checkOutputForStrategy() moving strategy %d to a2dp", strategy); + a2dpOutputDesc = mOutputs.valueFor(mA2dpOutput); + } + + for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { + if (getStrategy((AudioSystem::stream_type)i) == strategy) { + mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, mHardwareOutput); + int refCount = a2dpOutputDesc->mRefCount[i]; + // in the case of duplicated output, the ref count is first incremented + // and then decremented on hardware output tus keeping its value + hwOutputDesc->changeRefCount((AudioSystem::stream_type)i, refCount); + a2dpOutputDesc->changeRefCount((AudioSystem::stream_type)i,-refCount); + } + } + // do not change newDevice if it was already set before this call by a previous call to + // getNewDevice() or checkOutputForStrategy() for a strategy with higher priority + if (newDevice == 0 && hwOutputDesc->isUsedByStrategy(strategy)) { + newDevice = getDeviceForStrategy(strategy, false); + } + } + if (a2dpIsUsed && !a2dpWasUsed) { + bool dupUsed = a2dpUsedForSonification() && a2dpIsUsed && (AudioSystem::popCount(curDevice) == 2); + audio_io_handle_t a2dpOutput; + + if (dupUsed) { + LOGV("checkOutputForStrategy() moving strategy %d from duplicated", strategy); + a2dpOutputDesc = mOutputs.valueFor(mDuplicatedOutput); + a2dpOutput = mDuplicatedOutput; + } else { + LOGV("checkOutputForStrategy() moving strategy %d from a2dp", strategy); + a2dpOutputDesc = mOutputs.valueFor(mA2dpOutput); + a2dpOutput = mA2dpOutput; + } + + for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { + if (getStrategy((AudioSystem::stream_type)i) == strategy) { + mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, a2dpOutput); + int refCount = hwOutputDesc->mRefCount[i]; + // in the case of duplicated output, the ref count is first incremented + // and then decremented on hardware output tus keeping its value + a2dpOutputDesc->changeRefCount((AudioSystem::stream_type)i, refCount); + hwOutputDesc->changeRefCount((AudioSystem::stream_type)i,-refCount); + } + } + } +} + +void AudioPolicyManagerBase::checkOutputForAllStrategies(uint32_t &newDevice) +{ + // Check strategies in order of priority so that once newDevice is set + // for a given strategy it is not modified by subsequent calls to + // checkOutputForStrategy() + checkOutputForStrategy(STRATEGY_PHONE, newDevice); + checkOutputForStrategy(STRATEGY_SONIFICATION, newDevice); + checkOutputForStrategy(STRATEGY_MEDIA, newDevice); + checkOutputForStrategy(STRATEGY_DTMF, newDevice); +} + +#endif + +uint32_t AudioPolicyManagerBase::getNewDevice(audio_io_handle_t output, bool fromCache) +{ + uint32_t device = 0; + + AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); + // check the following by order of priority to request a routing change if necessary: + // 1: we are in call or the strategy phone is active on the hardware output: + // use device for strategy phone + // 2: the strategy sonification is active on the hardware output: + // use device for strategy sonification + // 3: the strategy media is active on the hardware output: + // use device for strategy media + // 4: the strategy DTMF is active on the hardware output: + // use device for strategy DTMF + if (mPhoneState == AudioSystem::MODE_IN_CALL || + outputDesc->isUsedByStrategy(STRATEGY_PHONE)) { + device = getDeviceForStrategy(STRATEGY_PHONE, fromCache); + } else if (outputDesc->isUsedByStrategy(STRATEGY_SONIFICATION)) { + device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache); + } else if (outputDesc->isUsedByStrategy(STRATEGY_MEDIA)) { + device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache); + } else if (outputDesc->isUsedByStrategy(STRATEGY_DTMF)) { + device = getDeviceForStrategy(STRATEGY_DTMF, fromCache); + } + + LOGV("getNewDevice() selected device %x", device); + return device; +} + +AudioPolicyManagerBase::routing_strategy AudioPolicyManagerBase::getStrategy(AudioSystem::stream_type stream) +{ + // stream to strategy mapping + switch (stream) { + case AudioSystem::VOICE_CALL: + case AudioSystem::BLUETOOTH_SCO: + return STRATEGY_PHONE; + case AudioSystem::RING: + case AudioSystem::NOTIFICATION: + case AudioSystem::ALARM: + case AudioSystem::ENFORCED_AUDIBLE: + return STRATEGY_SONIFICATION; + case AudioSystem::DTMF: + return STRATEGY_DTMF; + default: + LOGE("unknown stream type"); + case AudioSystem::SYSTEM: + // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs + // while key clicks are played produces a poor result + case AudioSystem::TTS: + case AudioSystem::MUSIC: + return STRATEGY_MEDIA; + } +} + +uint32_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy strategy, bool fromCache) +{ + uint32_t device = 0; + + if (fromCache) { + LOGV("getDeviceForStrategy() from cache strategy %d, device %x", strategy, mDeviceForStrategy[strategy]); + return mDeviceForStrategy[strategy]; + } + + switch (strategy) { + case STRATEGY_DTMF: + if (mPhoneState != AudioSystem::MODE_IN_CALL) { + // when off call, DTMF strategy follows the same rules as MEDIA strategy + device = getDeviceForStrategy(STRATEGY_MEDIA, false); + break; + } + // when in call, DTMF and PHONE strategies follow the same rules + // FALL THROUGH + + case STRATEGY_PHONE: + // for phone strategy, we first consider the forced use and then the available devices by order + // of priority + switch (mForceUse[AudioSystem::FOR_COMMUNICATION]) { + case AudioSystem::FORCE_BT_SCO: + if (mPhoneState != AudioSystem::MODE_IN_CALL || strategy != STRATEGY_DTMF) { + device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT; + if (device) break; + } + device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET; + if (device) break; + device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO; + if (device) break; + // if SCO device is requested but no SCO device is available, fall back to default case + // FALL THROUGH + + default: // FORCE_NONE + device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE; + if (device) break; + device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET; + if (device) break; +#ifdef WITH_A2DP + // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP + if (mPhoneState != AudioSystem::MODE_IN_CALL) { + device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP; + if (device) break; + device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; + if (device) break; + } +#endif + device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_EARPIECE; + if (device == 0) { + LOGE("getDeviceForStrategy() earpiece device not found"); + } + break; + + case AudioSystem::FORCE_SPEAKER: + if (mPhoneState != AudioSystem::MODE_IN_CALL || strategy != STRATEGY_DTMF) { + device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT; + if (device) break; + } +#ifdef WITH_A2DP + // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to + // A2DP speaker when forcing to speaker output + if (mPhoneState != AudioSystem::MODE_IN_CALL) { + device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; + if (device) break; + } +#endif + device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER; + if (device == 0) { + LOGE("getDeviceForStrategy() speaker device not found"); + } + break; + } + break; + + case STRATEGY_SONIFICATION: + + // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by + // handleIncallSonification(). + if (mPhoneState == AudioSystem::MODE_IN_CALL) { + device = getDeviceForStrategy(STRATEGY_PHONE, false); + break; + } + device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER; + if (device == 0) { + LOGE("getDeviceForStrategy() speaker device not found"); + } + // The second device used for sonification is the same as the device used by media strategy + // FALL THROUGH + + case STRATEGY_MEDIA: { + uint32_t device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL; + if (device2 == 0) { + device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE; + } + if (device2 == 0) { + device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET; + } +#ifdef WITH_A2DP + if (mA2dpOutput != 0) { + if (strategy == STRATEGY_SONIFICATION && !a2dpUsedForSonification()) { + break; + } + if (device2 == 0) { + device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP; + } + if (device2 == 0) { + device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; + } + if (device2 == 0) { + device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; + } + } +#endif + if (device2 == 0) { + device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER; + } + + // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION, 0 otherwise + device |= device2; + if (device == 0) { + LOGE("getDeviceForStrategy() speaker device not found"); + } + } break; + + default: + LOGW("getDeviceForStrategy() unknown strategy: %d", strategy); + break; + } + + LOGV("getDeviceForStrategy() strategy %d, device %x", strategy, device); + return device; +} + +void AudioPolicyManagerBase::updateDeviceForStrategy() +{ + for (int i = 0; i < NUM_STRATEGIES; i++) { + mDeviceForStrategy[i] = getDeviceForStrategy((routing_strategy)i, false); + } +} + +void AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output, uint32_t device, bool force, int delayMs) +{ + LOGV("setOutputDevice() output %d device %x delayMs %d", output, device, delayMs); + AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); + + + if (outputDesc->isDuplicated()) { + setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs); + setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs); + return; + } +#ifdef WITH_A2DP + // filter devices according to output selected + if (output == mA2dpOutput) { + device &= AudioSystem::DEVICE_OUT_ALL_A2DP; + } else { + device &= ~AudioSystem::DEVICE_OUT_ALL_A2DP; + } +#endif + + uint32_t prevDevice = (uint32_t)outputDesc->device(); + // Do not change the routing if: + // - the requestede device is 0 + // - the requested device is the same as current device and force is not specified. + // Doing this check here allows the caller to call setOutputDevice() without conditions + if ((device == 0 || device == prevDevice) && !force) { + LOGV("setOutputDevice() setting same device %x or null device for output %d", device, output); + return; + } + + outputDesc->mDevice = device; + // mute media streams if both speaker and headset are selected + if (output == mHardwareOutput && AudioSystem::popCount(device) == 2) { + setStrategyMute(STRATEGY_MEDIA, true, output); + // wait for the PCM output buffers to empty before proceeding with the rest of the command + usleep(outputDesc->mLatency*2*1000); + } +#ifdef WITH_A2DP + // suspend A2DP output if SCO device is selected + if (AudioSystem::isBluetoothScoDevice((AudioSystem::audio_devices)device)) { + if (mA2dpOutput != 0) { + mpClientInterface->suspendOutput(mA2dpOutput); + } + } +#endif + // do the routing + AudioParameter param = AudioParameter(); + param.addInt(String8(AudioParameter::keyRouting), (int)device); + mpClientInterface->setParameters(mHardwareOutput, param.toString(), delayMs); + // update stream volumes according to new device + applyStreamVolumes(output, device, delayMs); + +#ifdef WITH_A2DP + // if disconnecting SCO device, restore A2DP output + if (AudioSystem::isBluetoothScoDevice((AudioSystem::audio_devices)prevDevice)) { + if (mA2dpOutput != 0) { + LOGV("restore A2DP output"); + mpClientInterface->restoreOutput(mA2dpOutput); + } + } +#endif + // if changing from a combined headset + speaker route, unmute media streams + if (output == mHardwareOutput && AudioSystem::popCount(prevDevice) == 2) { + setStrategyMute(STRATEGY_MEDIA, false, output, delayMs); + } +} + +uint32_t AudioPolicyManagerBase::getDeviceForInputSource(int inputSource) +{ + uint32_t device; + + switch(inputSource) { + case AUDIO_SOURCE_DEFAULT: + case AUDIO_SOURCE_MIC: + case AUDIO_SOURCE_VOICE_RECOGNITION: + if (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO && + mAvailableInputDevices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET) { + device = AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET; + } else if (mAvailableInputDevices & AudioSystem::DEVICE_IN_WIRED_HEADSET) { + device = AudioSystem::DEVICE_IN_WIRED_HEADSET; + } else { + device = AudioSystem::DEVICE_IN_BUILTIN_MIC; + } + break; + case AUDIO_SOURCE_CAMCORDER: + if (hasBackMicrophone()) { + device = AudioSystem::DEVICE_IN_BACK_MIC; + } else { + device = AudioSystem::DEVICE_IN_BUILTIN_MIC; + } + break; + case AUDIO_SOURCE_VOICE_UPLINK: + case AUDIO_SOURCE_VOICE_DOWNLINK: + case AUDIO_SOURCE_VOICE_CALL: + device = AudioSystem::DEVICE_IN_VOICE_CALL; + break; + default: + LOGW("getInput() invalid input source %d", inputSource); + device = 0; + break; + } + LOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device); + return device; +} + +audio_io_handle_t AudioPolicyManagerBase::getActiveInput() +{ + for (size_t i = 0; i < mInputs.size(); i++) { + if (mInputs.valueAt(i)->mRefCount > 0) { + return mInputs.keyAt(i); + } + } + return 0; +} + +float AudioPolicyManagerBase::computeVolume(int stream, int index, audio_io_handle_t output, uint32_t device) +{ + float volume = 1.0; + AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); + StreamDescriptor &streamDesc = mStreams[stream]; + + if (device == 0) { + device = outputDesc->device(); + } + + int volInt = (100 * (index - streamDesc.mIndexMin)) / (streamDesc.mIndexMax - streamDesc.mIndexMin); + volume = AudioSystem::linearToLog(volInt); + + // if a headset is connected, apply the following rules to ring tones and notifications + // to avoid sound level bursts in user's ears: + // - always attenuate ring tones and notifications volume by 6dB + // - if music is playing, always limit the volume to current music volume, + // with a minimum threshold at -36dB so that notification is always perceived. + if ((device & + (AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP | + AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | + AudioSystem::DEVICE_OUT_WIRED_HEADSET | + AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) && + (getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) && + streamDesc.mCanBeMuted) { + volume *= SONIFICATION_HEADSET_VOLUME_FACTOR; + // when the phone is ringing we must consider that music could have been paused just before + // by the music application and behave as if music was active if the last music track was + // just stopped + if (outputDesc->mRefCount[AudioSystem::MUSIC] || mLimitRingtoneVolume) { + float musicVol = computeVolume(AudioSystem::MUSIC, mStreams[AudioSystem::MUSIC].mIndexCur, output, device); + float minVol = (musicVol > SONIFICATION_HEADSET_VOLUME_MIN) ? musicVol : SONIFICATION_HEADSET_VOLUME_MIN; + if (volume > minVol) { + volume = minVol; + LOGV("computeVolume limiting volume to %f musicVol %f", minVol, musicVol); + } + } + } + + return volume; +} + +status_t AudioPolicyManagerBase::checkAndSetVolume(int stream, int index, audio_io_handle_t output, uint32_t device, int delayMs, bool force) +{ + + // do not change actual stream volume if the stream is muted + if (mOutputs.valueFor(output)->mMuteCount[stream] != 0) { + LOGV("checkAndSetVolume() stream %d muted count %d", stream, mOutputs.valueFor(output)->mMuteCount[stream]); + return NO_ERROR; + } + + // do not change in call volume if bluetooth is connected and vice versa + if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) || + (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) { + LOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm", + stream, mForceUse[AudioSystem::FOR_COMMUNICATION]); + return INVALID_OPERATION; + } + + float volume = computeVolume(stream, index, output, device); + // do not set volume if the float value did not change + if (volume != mOutputs.valueFor(output)->mCurVolume[stream] || force) { + mOutputs.valueFor(output)->mCurVolume[stream] = volume; + LOGV("setStreamVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs); + if (stream == AudioSystem::VOICE_CALL || + stream == AudioSystem::DTMF || + stream == AudioSystem::BLUETOOTH_SCO) { + float voiceVolume = -1.0; + // offset value to reflect actual hardware volume that never reaches 0 + // 1% corresponds roughly to first step in VOICE_CALL stream volume setting (see AudioService.java) + volume = 0.01 + 0.99 * volume; + if (stream == AudioSystem::VOICE_CALL) { + voiceVolume = (float)index/(float)mStreams[stream].mIndexMax; + } else if (stream == AudioSystem::BLUETOOTH_SCO) { + voiceVolume = 1.0; + } + if (voiceVolume >= 0 && output == mHardwareOutput) { + mpClientInterface->setVoiceVolume(voiceVolume, delayMs); + } + } + mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs); + } + + return NO_ERROR; +} + +void AudioPolicyManagerBase::applyStreamVolumes(audio_io_handle_t output, uint32_t device, int delayMs) +{ + LOGV("applyStreamVolumes() for output %d and device %x", output, device); + + for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { + checkAndSetVolume(stream, mStreams[stream].mIndexCur, output, device, delayMs); + } +} + +void AudioPolicyManagerBase::setStrategyMute(routing_strategy strategy, bool on, audio_io_handle_t output, int delayMs) +{ + LOGV("setStrategyMute() strategy %d, mute %d, output %d", strategy, on, output); + for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { + if (getStrategy((AudioSystem::stream_type)stream) == strategy) { + setStreamMute(stream, on, output, delayMs); + } + } +} + +void AudioPolicyManagerBase::setStreamMute(int stream, bool on, audio_io_handle_t output, int delayMs) +{ + StreamDescriptor &streamDesc = mStreams[stream]; + AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); + + LOGV("setStreamMute() stream %d, mute %d, output %d, mMuteCount %d", stream, on, output, outputDesc->mMuteCount[stream]); + + if (on) { + if (outputDesc->mMuteCount[stream] == 0) { + if (streamDesc.mCanBeMuted) { + checkAndSetVolume(stream, 0, output, outputDesc->device(), delayMs); + } + } + // increment mMuteCount after calling checkAndSetVolume() so that volume change is not ignored + outputDesc->mMuteCount[stream]++; + } else { + if (outputDesc->mMuteCount[stream] == 0) { + LOGW("setStreamMute() unmuting non muted stream!"); + return; + } + if (--outputDesc->mMuteCount[stream] == 0) { + checkAndSetVolume(stream, streamDesc.mIndexCur, output, outputDesc->device(), delayMs); + } + } +} + +void AudioPolicyManagerBase::handleIncallSonification(int stream, bool starting, bool stateChange) +{ + // if the stream pertains to sonification strategy and we are in call we must + // mute the stream if it is low visibility. If it is high visibility, we must play a tone + // in the device used for phone strategy and play the tone if the selected device does not + // interfere with the device used for phone strategy + // if stateChange is true, we are called from setPhoneState() and we must mute or unmute as + // many times as there are active tracks on the output + + if (getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) { + AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mHardwareOutput); + LOGV("handleIncallSonification() stream %d starting %d device %x stateChange %d", + stream, starting, outputDesc->mDevice, stateChange); + if (outputDesc->mRefCount[stream]) { + int muteCount = 1; + if (stateChange) { + muteCount = outputDesc->mRefCount[stream]; + } + if (AudioSystem::isLowVisibility((AudioSystem::stream_type)stream)) { + LOGV("handleIncallSonification() low visibility, muteCount %d", muteCount); + for (int i = 0; i < muteCount; i++) { + setStreamMute(stream, starting, mHardwareOutput); + } + } else { + LOGV("handleIncallSonification() high visibility"); + if (outputDesc->device() & getDeviceForStrategy(STRATEGY_PHONE)) { + LOGV("handleIncallSonification() high visibility muted, muteCount %d", muteCount); + for (int i = 0; i < muteCount; i++) { + setStreamMute(stream, starting, mHardwareOutput); + } + } + if (starting) { + mpClientInterface->startTone(ToneGenerator::TONE_SUP_CALL_WAITING, AudioSystem::VOICE_CALL); + } else { + mpClientInterface->stopTone(); + } + } + } + } +} + +bool AudioPolicyManagerBase::needsDirectOuput(AudioSystem::stream_type stream, + uint32_t samplingRate, + uint32_t format, + uint32_t channels, + AudioSystem::output_flags flags, + uint32_t device) +{ + return ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) || + (format !=0 && !AudioSystem::isLinearPCM(format))); +} + +// --- AudioOutputDescriptor class implementation + +AudioPolicyManagerBase::AudioOutputDescriptor::AudioOutputDescriptor() + : mId(0), mSamplingRate(0), mFormat(0), mChannels(0), mLatency(0), + mFlags((AudioSystem::output_flags)0), mDevice(0), mOutput1(0), mOutput2(0) +{ + // clear usage count for all stream types + for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) { + mRefCount[i] = 0; + mCurVolume[i] = -1.0; + mMuteCount[i] = 0; + } +} + +uint32_t AudioPolicyManagerBase::AudioOutputDescriptor::device() +{ + uint32_t device = 0; + if (isDuplicated()) { + device = mOutput1->mDevice | mOutput2->mDevice; + } else { + device = mDevice; + } + return device; +} + +void AudioPolicyManagerBase::AudioOutputDescriptor::changeRefCount(AudioSystem::stream_type stream, int delta) +{ + // forward usage count change to attached outputs + if (isDuplicated()) { + mOutput1->changeRefCount(stream, delta); + mOutput2->changeRefCount(stream, delta); + } + if ((delta + (int)mRefCount[stream]) < 0) { + LOGW("changeRefCount() invalid delta %d for stream %d, refCount %d", delta, stream, mRefCount[stream]); + mRefCount[stream] = 0; + return; + } + mRefCount[stream] += delta; + LOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]); +} + +uint32_t AudioPolicyManagerBase::AudioOutputDescriptor::refCount() +{ + uint32_t refcount = 0; + for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { + refcount += mRefCount[i]; + } + return refcount; +} + +uint32_t AudioPolicyManagerBase::AudioOutputDescriptor::strategyRefCount(routing_strategy strategy) +{ + uint32_t refCount = 0; + for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { + if (getStrategy((AudioSystem::stream_type)i) == strategy) { + refCount += mRefCount[i]; + } + } + return refCount; +} + + +status_t AudioPolicyManagerBase::AudioOutputDescriptor::dump(int fd) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate); + result.append(buffer); + snprintf(buffer, SIZE, " Format: %d\n", mFormat); + result.append(buffer); + snprintf(buffer, SIZE, " Channels: %08x\n", mChannels); + result.append(buffer); + snprintf(buffer, SIZE, " Latency: %d\n", mLatency); + result.append(buffer); + snprintf(buffer, SIZE, " Flags %08x\n", mFlags); + result.append(buffer); + snprintf(buffer, SIZE, " Devices %08x\n", device()); + result.append(buffer); + snprintf(buffer, SIZE, " Stream volume refCount muteCount\n"); + result.append(buffer); + for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) { + snprintf(buffer, SIZE, " %02d %.03f %02d %02d\n", i, mCurVolume[i], mRefCount[i], mMuteCount[i]); + result.append(buffer); + } + write(fd, result.string(), result.size()); + + return NO_ERROR; +} + +// --- AudioInputDescriptor class implementation + +AudioPolicyManagerBase::AudioInputDescriptor::AudioInputDescriptor() + : mSamplingRate(0), mFormat(0), mChannels(0), + mAcoustics((AudioSystem::audio_in_acoustics)0), mDevice(0), mRefCount(0) +{ +} + +status_t AudioPolicyManagerBase::AudioInputDescriptor::dump(int fd) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate); + result.append(buffer); + snprintf(buffer, SIZE, " Format: %d\n", mFormat); + result.append(buffer); + snprintf(buffer, SIZE, " Channels: %08x\n", mChannels); + result.append(buffer); + snprintf(buffer, SIZE, " Acoustics %08x\n", mAcoustics); + result.append(buffer); + snprintf(buffer, SIZE, " Devices %08x\n", mDevice); + result.append(buffer); + snprintf(buffer, SIZE, " Ref Count %d\n", mRefCount); + result.append(buffer); + write(fd, result.string(), result.size()); + + return NO_ERROR; +} + +// --- StreamDescriptor class implementation + +void AudioPolicyManagerBase::StreamDescriptor::dump(char* buffer, size_t size) +{ + snprintf(buffer, size, " %02d %02d %02d %d\n", + mIndexMin, + mIndexMax, + mIndexCur, + mCanBeMuted); +} + + +}; // namespace android diff --git a/libs/audioflinger/AudioPolicyManagerGeneric.cpp b/libs/audioflinger/AudioPolicyManagerGeneric.cpp deleted file mode 100644 index 8cfc204..0000000 --- a/libs/audioflinger/AudioPolicyManagerGeneric.cpp +++ /dev/null @@ -1,945 +0,0 @@ -/* - * Copyright (C) 2009 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 "AudioPolicyManagerGeneric" -//#define LOG_NDEBUG 0 -#include <utils/Log.h> -#include "AudioPolicyManagerGeneric.h" -#include <media/mediarecorder.h> - -namespace android { - - -// ---------------------------------------------------------------------------- -// AudioPolicyInterface implementation -// ---------------------------------------------------------------------------- - - -status_t AudioPolicyManagerGeneric::setDeviceConnectionState(AudioSystem::audio_devices device, - AudioSystem::device_connection_state state, - const char *device_address) -{ - - LOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address); - - // connect/disconnect only 1 device at a time - if (AudioSystem::popCount(device) != 1) return BAD_VALUE; - - if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) { - LOGE("setDeviceConnectionState() invalid address: %s", device_address); - return BAD_VALUE; - } - - // handle output devices - if (AudioSystem::isOutputDevice(device)) { - switch (state) - { - // handle output device connection - case AudioSystem::DEVICE_STATE_AVAILABLE: - if (mAvailableOutputDevices & device) { - LOGW("setDeviceConnectionState() device already connected: %x", device); - return INVALID_OPERATION; - } - LOGV("setDeviceConnectionState() connecting device %x", device); - - // register new device as available - mAvailableOutputDevices |= device; - break; - // handle output device disconnection - case AudioSystem::DEVICE_STATE_UNAVAILABLE: - if (!(mAvailableOutputDevices & device)) { - LOGW("setDeviceConnectionState() device not connected: %x", device); - return INVALID_OPERATION; - } - LOGV("setDeviceConnectionState() disconnecting device %x", device); - // remove device from available output devices - mAvailableOutputDevices &= ~device; - break; - - default: - LOGE("setDeviceConnectionState() invalid state: %x", state); - return BAD_VALUE; - } - return NO_ERROR; - } - // handle input devices - if (AudioSystem::isInputDevice(device)) { - switch (state) - { - // handle input device connection - case AudioSystem::DEVICE_STATE_AVAILABLE: - if (mAvailableInputDevices & device) { - LOGW("setDeviceConnectionState() device already connected: %d", device); - return INVALID_OPERATION; - } - mAvailableInputDevices |= device; - break; - - // handle input device disconnection - case AudioSystem::DEVICE_STATE_UNAVAILABLE: - if (!(mAvailableInputDevices & device)) { - LOGW("setDeviceConnectionState() device not connected: %d", device); - return INVALID_OPERATION; - } - mAvailableInputDevices &= ~device; - break; - - default: - LOGE("setDeviceConnectionState() invalid state: %x", state); - return BAD_VALUE; - } - return NO_ERROR; - } - - LOGW("setDeviceConnectionState() invalid device: %x", device); - return BAD_VALUE; -} - -AudioSystem::device_connection_state AudioPolicyManagerGeneric::getDeviceConnectionState(AudioSystem::audio_devices device, - const char *device_address) -{ - AudioSystem::device_connection_state state = AudioSystem::DEVICE_STATE_UNAVAILABLE; - String8 address = String8(device_address); - if (AudioSystem::isOutputDevice(device)) { - if (device & mAvailableOutputDevices) { - state = AudioSystem::DEVICE_STATE_AVAILABLE; - } - } else if (AudioSystem::isInputDevice(device)) { - if (device & mAvailableInputDevices) { - state = AudioSystem::DEVICE_STATE_AVAILABLE; - } - } - - return state; -} - -void AudioPolicyManagerGeneric::setPhoneState(int state) -{ - LOGV("setPhoneState() state %d", state); - uint32_t newDevice = 0; - if (state < 0 || state >= AudioSystem::NUM_MODES) { - LOGW("setPhoneState() invalid state %d", state); - return; - } - - if (state == mPhoneState ) { - LOGW("setPhoneState() setting same state %d", state); - return; - } - // store previous phone state for management of sonification strategy below - int oldState = mPhoneState; - mPhoneState = state; - - // if leaving or entering in call state, handle special case of active streams - // pertaining to sonification strategy see handleIncallSonification() - if (state == AudioSystem::MODE_IN_CALL || - oldState == AudioSystem::MODE_IN_CALL) { - bool starting = (state == AudioSystem::MODE_IN_CALL) ? true : false; - LOGV("setPhoneState() in call state management: new state is %d", state); - for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { - handleIncallSonification(stream, starting); - } - } -} - -void AudioPolicyManagerGeneric::setRingerMode(uint32_t mode, uint32_t mask) -{ - LOGV("setRingerMode() mode %x, mask %x", mode, mask); - - mRingerMode = mode; -} - -void AudioPolicyManagerGeneric::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) -{ - LOGV("setForceUse) usage %d, config %d, mPhoneState %d", usage, config, mPhoneState); - mForceUse[usage] = config; -} - -AudioSystem::forced_config AudioPolicyManagerGeneric::getForceUse(AudioSystem::force_use usage) -{ - return mForceUse[usage]; -} - -void AudioPolicyManagerGeneric::setSystemProperty(const char* property, const char* value) -{ - LOGV("setSystemProperty() property %s, value %s", property, value); - if (strcmp(property, "ro.camera.sound.forced") == 0) { - if (atoi(value)) { - LOGV("ENFORCED_AUDIBLE cannot be muted"); - mStreams[AudioSystem::ENFORCED_AUDIBLE].mCanBeMuted = false; - } else { - LOGV("ENFORCED_AUDIBLE can be muted"); - mStreams[AudioSystem::ENFORCED_AUDIBLE].mCanBeMuted = true; - } - } -} - -audio_io_handle_t AudioPolicyManagerGeneric::getOutput(AudioSystem::stream_type stream, - uint32_t samplingRate, - uint32_t format, - uint32_t channels, - AudioSystem::output_flags flags) -{ - LOGV("getOutput() stream %d, samplingRate %d, format %d, channels %x, flags %x", stream, samplingRate, format, channels, flags); - -#ifdef AUDIO_POLICY_TEST - if (mCurOutput != 0) { - LOGV("getOutput() test output mCurOutput %d, samplingRate %d, format %d, channels %x, mDirectOutput %d", - mCurOutput, mTestSamplingRate, mTestFormat, mTestChannels, mDirectOutput); - - if (mTestOutputs[mCurOutput] == 0) { - LOGV("getOutput() opening test output"); - AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(); - outputDesc->mDevice = mTestDevice; - outputDesc->mSamplingRate = mTestSamplingRate; - outputDesc->mFormat = mTestFormat; - outputDesc->mChannels = mTestChannels; - outputDesc->mLatency = mTestLatencyMs; - outputDesc->mFlags = (AudioSystem::output_flags)(mDirectOutput ? AudioSystem::OUTPUT_FLAG_DIRECT : 0); - outputDesc->mRefCount[stream] = 0; - mTestOutputs[mCurOutput] = mpClientInterface->openOutput(&outputDesc->mDevice, - &outputDesc->mSamplingRate, - &outputDesc->mFormat, - &outputDesc->mChannels, - &outputDesc->mLatency, - outputDesc->mFlags); - if (mTestOutputs[mCurOutput]) { - AudioParameter outputCmd = AudioParameter(); - outputCmd.addInt(String8("set_id"),mCurOutput); - mpClientInterface->setParameters(mTestOutputs[mCurOutput],outputCmd.toString()); - mOutputs.add(mTestOutputs[mCurOutput], outputDesc); - } - } - return mTestOutputs[mCurOutput]; - } -#endif //AUDIO_POLICY_TEST - if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) || - (format != 0 && !AudioSystem::isLinearPCM(format)) || - (channels != 0 && channels != AudioSystem::CHANNEL_OUT_MONO && channels != AudioSystem::CHANNEL_OUT_STEREO)) { - return 0; - } - - return mHardwareOutput; -} - -status_t AudioPolicyManagerGeneric::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream) -{ - LOGV("startOutput() output %d, stream %d", output, stream); - ssize_t index = mOutputs.indexOfKey(output); - if (index < 0) { - LOGW("startOutput() unknow output %d", output); - return BAD_VALUE; - } - - AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); - - // handle special case for sonification while in call - if (mPhoneState == AudioSystem::MODE_IN_CALL) { - handleIncallSonification(stream, true); - } - - // incremenent usage count for this stream on the requested output: - outputDesc->changeRefCount(stream, 1); - return NO_ERROR; -} - -status_t AudioPolicyManagerGeneric::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream) -{ - LOGV("stopOutput() output %d, stream %d", output, stream); - ssize_t index = mOutputs.indexOfKey(output); - if (index < 0) { - LOGW("stopOutput() unknow output %d", output); - return BAD_VALUE; - } - - AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); - - // handle special case for sonification while in call - if (mPhoneState == AudioSystem::MODE_IN_CALL) { - handleIncallSonification(stream, false); - } - - if (outputDesc->isUsedByStream(stream)) { - // decrement usage count of this stream on the output - outputDesc->changeRefCount(stream, -1); - return NO_ERROR; - } else { - LOGW("stopOutput() refcount is already 0 for output %d", output); - return INVALID_OPERATION; - } -} - -void AudioPolicyManagerGeneric::releaseOutput(audio_io_handle_t output) -{ - LOGV("releaseOutput() %d", output); - ssize_t index = mOutputs.indexOfKey(output); - if (index < 0) { - LOGW("releaseOutput() releasing unknown output %d", output); - return; - } - -#ifdef AUDIO_POLICY_TEST - int testIndex = testOutputIndex(output); - if (testIndex != 0) { - AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); - if (outputDesc->refCount() == 0) { - mpClientInterface->closeOutput(output); - delete mOutputs.valueAt(index); - mOutputs.removeItem(output); - mTestOutputs[testIndex] = 0; - } - } -#endif //AUDIO_POLICY_TEST -} - -audio_io_handle_t AudioPolicyManagerGeneric::getInput(int inputSource, - uint32_t samplingRate, - uint32_t format, - uint32_t channels, - AudioSystem::audio_in_acoustics acoustics) -{ - audio_io_handle_t input = 0; - uint32_t device; - - LOGV("getInput() inputSource %d, samplingRate %d, format %d, channels %x, acoustics %x", inputSource, samplingRate, format, channels, acoustics); - - AudioInputDescriptor *inputDesc = new AudioInputDescriptor(); - inputDesc->mDevice = AudioSystem::DEVICE_IN_BUILTIN_MIC; - inputDesc->mSamplingRate = samplingRate; - inputDesc->mFormat = format; - inputDesc->mChannels = channels; - inputDesc->mAcoustics = acoustics; - inputDesc->mRefCount = 0; - input = mpClientInterface->openInput(&inputDesc->mDevice, - &inputDesc->mSamplingRate, - &inputDesc->mFormat, - &inputDesc->mChannels, - inputDesc->mAcoustics); - - // only accept input with the exact requested set of parameters - if ((samplingRate != inputDesc->mSamplingRate) || - (format != inputDesc->mFormat) || - (channels != inputDesc->mChannels)) { - LOGV("getOutput() failed opening input: samplingRate %d, format %d, channels %d", - samplingRate, format, channels); - mpClientInterface->closeInput(input); - delete inputDesc; - return 0; - } - mInputs.add(input, inputDesc); - return input; -} - -status_t AudioPolicyManagerGeneric::startInput(audio_io_handle_t input) -{ - LOGV("startInput() input %d", input); - ssize_t index = mInputs.indexOfKey(input); - if (index < 0) { - LOGW("startInput() unknow input %d", input); - return BAD_VALUE; - } - AudioInputDescriptor *inputDesc = mInputs.valueAt(index); - -#ifdef AUDIO_POLICY_TEST - if (mTestInput == 0) -#endif //AUDIO_POLICY_TEST - { - // refuse 2 active AudioRecord clients at the same time - for (size_t i = 0; i < mInputs.size(); i++) { - if (mInputs.valueAt(i)->mRefCount > 0) { - LOGW("startInput() input %d, other input %d already started", input, mInputs.keyAt(i)); - return INVALID_OPERATION; - } - } - } - - inputDesc->mRefCount = 1; - return NO_ERROR; -} - -status_t AudioPolicyManagerGeneric::stopInput(audio_io_handle_t input) -{ - LOGV("stopInput() input %d", input); - ssize_t index = mInputs.indexOfKey(input); - if (index < 0) { - LOGW("stopInput() unknow input %d", input); - return BAD_VALUE; - } - AudioInputDescriptor *inputDesc = mInputs.valueAt(index); - - if (inputDesc->mRefCount == 0) { - LOGW("stopInput() input %d already stopped", input); - return INVALID_OPERATION; - } else { - inputDesc->mRefCount = 0; - return NO_ERROR; - } -} - -void AudioPolicyManagerGeneric::releaseInput(audio_io_handle_t input) -{ - LOGV("releaseInput() %d", input); - ssize_t index = mInputs.indexOfKey(input); - if (index < 0) { - LOGW("releaseInput() releasing unknown input %d", input); - return; - } - mpClientInterface->closeInput(input); - delete mInputs.valueAt(index); - mInputs.removeItem(input); -} - - - -void AudioPolicyManagerGeneric::initStreamVolume(AudioSystem::stream_type stream, - int indexMin, - int indexMax) -{ - LOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax); - mStreams[stream].mIndexMin = indexMin; - mStreams[stream].mIndexMax = indexMax; -} - -status_t AudioPolicyManagerGeneric::setStreamVolumeIndex(AudioSystem::stream_type stream, int index) -{ - - if ((index < mStreams[stream].mIndexMin) || (index > mStreams[stream].mIndexMax)) { - return BAD_VALUE; - } - - LOGV("setStreamVolumeIndex() stream %d, index %d", stream, index); - mStreams[stream].mIndexCur = index; - - // do not change actual stream volume if the stream is muted - if (mStreams[stream].mMuteCount != 0) { - return NO_ERROR; - } - - // Do not changed in call volume if bluetooth is connected and vice versa - if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) || - (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) { - LOGV("setStreamVolumeIndex() cannot set stream %d volume with force use = %d for comm", - stream, mForceUse[AudioSystem::FOR_COMMUNICATION]); - return INVALID_OPERATION; - } - - // compute and apply stream volume on all outputs according to connected device - for (size_t i = 0; i < mOutputs.size(); i++) { - AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i); - uint32_t device = outputDesc->device(); - - float volume = computeVolume((int)stream, index, device); - - LOGV("setStreamVolume() for output %d stream %d, volume %f", mOutputs.keyAt(i), stream, volume); - mpClientInterface->setStreamVolume(stream, volume, mOutputs.keyAt(i)); - } - return NO_ERROR; -} - -status_t AudioPolicyManagerGeneric::getStreamVolumeIndex(AudioSystem::stream_type stream, int *index) -{ - if (index == 0) { - return BAD_VALUE; - } - LOGV("getStreamVolumeIndex() stream %d", stream); - *index = mStreams[stream].mIndexCur; - return NO_ERROR; -} - -status_t AudioPolicyManagerGeneric::dump(int fd) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - - snprintf(buffer, SIZE, "\nAudioPolicyManager Dump: %p\n", this); - result.append(buffer); - snprintf(buffer, SIZE, " Hardware Output: %d\n", mHardwareOutput); - result.append(buffer); - snprintf(buffer, SIZE, " Output devices: %08x\n", mAvailableOutputDevices); - result.append(buffer); - snprintf(buffer, SIZE, " Input devices: %08x\n", mAvailableInputDevices); - result.append(buffer); - snprintf(buffer, SIZE, " Phone state: %d\n", mPhoneState); - result.append(buffer); - snprintf(buffer, SIZE, " Ringer mode: %d\n", mRingerMode); - result.append(buffer); - snprintf(buffer, SIZE, " Force use for communications %d\n", mForceUse[AudioSystem::FOR_COMMUNICATION]); - result.append(buffer); - snprintf(buffer, SIZE, " Force use for media %d\n", mForceUse[AudioSystem::FOR_MEDIA]); - result.append(buffer); - snprintf(buffer, SIZE, " Force use for record %d\n", mForceUse[AudioSystem::FOR_RECORD]); - result.append(buffer); - write(fd, result.string(), result.size()); - - snprintf(buffer, SIZE, "\nOutputs dump:\n"); - write(fd, buffer, strlen(buffer)); - for (size_t i = 0; i < mOutputs.size(); i++) { - snprintf(buffer, SIZE, "- Output %d dump:\n", mOutputs.keyAt(i)); - write(fd, buffer, strlen(buffer)); - mOutputs.valueAt(i)->dump(fd); - } - - snprintf(buffer, SIZE, "\nInputs dump:\n"); - write(fd, buffer, strlen(buffer)); - for (size_t i = 0; i < mInputs.size(); i++) { - snprintf(buffer, SIZE, "- Input %d dump:\n", mInputs.keyAt(i)); - write(fd, buffer, strlen(buffer)); - mInputs.valueAt(i)->dump(fd); - } - - snprintf(buffer, SIZE, "\nStreams dump:\n"); - write(fd, buffer, strlen(buffer)); - snprintf(buffer, SIZE, " Stream Index Min Index Max Index Cur Mute Count Can be muted\n"); - write(fd, buffer, strlen(buffer)); - for (size_t i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) { - snprintf(buffer, SIZE, " %02d", i); - mStreams[i].dump(buffer + 3, SIZE); - write(fd, buffer, strlen(buffer)); - } - - return NO_ERROR; -} - -// ---------------------------------------------------------------------------- -// AudioPolicyManagerGeneric -// ---------------------------------------------------------------------------- - -// --- class factory - -AudioPolicyManagerGeneric::AudioPolicyManagerGeneric(AudioPolicyClientInterface *clientInterface) - : -#ifdef AUDIO_POLICY_TEST - Thread(false), -#endif //AUDIO_POLICY_TEST - mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0) -{ - mpClientInterface = clientInterface; - - for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) { - mForceUse[i] = AudioSystem::FORCE_NONE; - } - - // devices available by default are speaker, ear piece and microphone - mAvailableOutputDevices = AudioSystem::DEVICE_OUT_SPEAKER; - mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC; - - // open hardware output - AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(); - outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER; - mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice, - &outputDesc->mSamplingRate, - &outputDesc->mFormat, - &outputDesc->mChannels, - &outputDesc->mLatency, - outputDesc->mFlags); - - if (mHardwareOutput == 0) { - LOGE("Failed to initialize hardware output stream, samplingRate: %d, format %d, channels %d", - outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannels); - } else { - mOutputs.add(mHardwareOutput, outputDesc); - } - -#ifdef AUDIO_POLICY_TEST - AudioParameter outputCmd = AudioParameter(); - outputCmd.addInt(String8("set_id"), 0); - mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString()); - - mTestDevice = AudioSystem::DEVICE_OUT_SPEAKER; - mTestSamplingRate = 44100; - mTestFormat = AudioSystem::PCM_16_BIT; - mTestChannels = AudioSystem::CHANNEL_OUT_STEREO; - mTestLatencyMs = 0; - mCurOutput = 0; - mDirectOutput = false; - for (int i = 0; i < NUM_TEST_OUTPUTS; i++) { - mTestOutputs[i] = 0; - } - - const size_t SIZE = 256; - char buffer[SIZE]; - snprintf(buffer, SIZE, "AudioPolicyManagerTest"); - run(buffer, ANDROID_PRIORITY_AUDIO); -#endif //AUDIO_POLICY_TEST -} - -AudioPolicyManagerGeneric::~AudioPolicyManagerGeneric() -{ -#ifdef AUDIO_POLICY_TEST - exit(); -#endif //AUDIO_POLICY_TEST - - for (size_t i = 0; i < mOutputs.size(); i++) { - mpClientInterface->closeOutput(mOutputs.keyAt(i)); - delete mOutputs.valueAt(i); - } - mOutputs.clear(); - for (size_t i = 0; i < mInputs.size(); i++) { - mpClientInterface->closeInput(mInputs.keyAt(i)); - delete mInputs.valueAt(i); - } - mInputs.clear(); -} - -#ifdef AUDIO_POLICY_TEST -bool AudioPolicyManagerGeneric::threadLoop() -{ - LOGV("entering threadLoop()"); - while (!exitPending()) - { - String8 command; - int valueInt; - String8 value; - - Mutex::Autolock _l(mLock); - mWaitWorkCV.waitRelative(mLock, milliseconds(50)); - - command = mpClientInterface->getParameters(0, String8("test_cmd_policy")); - AudioParameter param = AudioParameter(command); - - if (param.getInt(String8("test_cmd_policy"), valueInt) == NO_ERROR && - valueInt != 0) { - LOGV("Test command %s received", command.string()); - String8 target; - if (param.get(String8("target"), target) != NO_ERROR) { - target = "Manager"; - } - if (param.getInt(String8("test_cmd_policy_output"), valueInt) == NO_ERROR) { - param.remove(String8("test_cmd_policy_output")); - mCurOutput = valueInt; - } - if (param.get(String8("test_cmd_policy_direct"), value) == NO_ERROR) { - param.remove(String8("test_cmd_policy_direct")); - if (value == "false") { - mDirectOutput = false; - } else if (value == "true") { - mDirectOutput = true; - } - } - if (param.getInt(String8("test_cmd_policy_input"), valueInt) == NO_ERROR) { - param.remove(String8("test_cmd_policy_input")); - mTestInput = valueInt; - } - - if (param.get(String8("test_cmd_policy_format"), value) == NO_ERROR) { - param.remove(String8("test_cmd_policy_format")); - int format = AudioSystem::INVALID_FORMAT; - if (value == "PCM 16 bits") { - format = AudioSystem::PCM_16_BIT; - } else if (value == "PCM 8 bits") { - format = AudioSystem::PCM_8_BIT; - } else if (value == "Compressed MP3") { - format = AudioSystem::MP3; - } - if (format != AudioSystem::INVALID_FORMAT) { - if (target == "Manager") { - mTestFormat = format; - } else if (mTestOutputs[mCurOutput] != 0) { - AudioParameter outputParam = AudioParameter(); - outputParam.addInt(String8("format"), format); - mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString()); - } - } - } - if (param.get(String8("test_cmd_policy_channels"), value) == NO_ERROR) { - param.remove(String8("test_cmd_policy_channels")); - int channels = 0; - - if (value == "Channels Stereo") { - channels = AudioSystem::CHANNEL_OUT_STEREO; - } else if (value == "Channels Mono") { - channels = AudioSystem::CHANNEL_OUT_MONO; - } - if (channels != 0) { - if (target == "Manager") { - mTestChannels = channels; - } else if (mTestOutputs[mCurOutput] != 0) { - AudioParameter outputParam = AudioParameter(); - outputParam.addInt(String8("channels"), channels); - mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString()); - } - } - } - if (param.getInt(String8("test_cmd_policy_sampleRate"), valueInt) == NO_ERROR) { - param.remove(String8("test_cmd_policy_sampleRate")); - if (valueInt >= 0 && valueInt <= 96000) { - int samplingRate = valueInt; - if (target == "Manager") { - mTestSamplingRate = samplingRate; - } else if (mTestOutputs[mCurOutput] != 0) { - AudioParameter outputParam = AudioParameter(); - outputParam.addInt(String8("sampling_rate"), samplingRate); - mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString()); - } - } - } - - if (param.get(String8("test_cmd_policy_reopen"), value) == NO_ERROR) { - param.remove(String8("test_cmd_policy_reopen")); - - mpClientInterface->closeOutput(mHardwareOutput); - delete mOutputs.valueFor(mHardwareOutput); - mOutputs.removeItem(mHardwareOutput); - - AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(); - outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER; - mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice, - &outputDesc->mSamplingRate, - &outputDesc->mFormat, - &outputDesc->mChannels, - &outputDesc->mLatency, - outputDesc->mFlags); - if (mHardwareOutput == 0) { - LOGE("Failed to reopen hardware output stream, samplingRate: %d, format %d, channels %d", - outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannels); - } else { - AudioParameter outputCmd = AudioParameter(); - outputCmd.addInt(String8("set_id"), 0); - mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString()); - mOutputs.add(mHardwareOutput, outputDesc); - } - } - - - mpClientInterface->setParameters(0, String8("test_cmd_policy=")); - } - } - return false; -} - -void AudioPolicyManagerGeneric::exit() -{ - { - AutoMutex _l(mLock); - requestExit(); - mWaitWorkCV.signal(); - } - requestExitAndWait(); -} - -int AudioPolicyManagerGeneric::testOutputIndex(audio_io_handle_t output) -{ - for (int i = 0; i < NUM_TEST_OUTPUTS; i++) { - if (output == mTestOutputs[i]) return i; - } - return 0; -} -#endif //AUDIO_POLICY_TEST - -// --- - -AudioPolicyManagerGeneric::routing_strategy AudioPolicyManagerGeneric::getStrategy(AudioSystem::stream_type stream) -{ - // stream to strategy mapping - switch (stream) { - case AudioSystem::VOICE_CALL: - case AudioSystem::BLUETOOTH_SCO: - return STRATEGY_PHONE; - case AudioSystem::RING: - case AudioSystem::NOTIFICATION: - case AudioSystem::ALARM: - case AudioSystem::ENFORCED_AUDIBLE: - return STRATEGY_SONIFICATION; - case AudioSystem::DTMF: - return STRATEGY_DTMF; - default: - LOGE("unknown stream type"); - case AudioSystem::SYSTEM: - // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs - // while key clicks are played produces a poor result - case AudioSystem::TTS: - case AudioSystem::MUSIC: - return STRATEGY_MEDIA; - } -} - - -float AudioPolicyManagerGeneric::computeVolume(int stream, int index, uint32_t device) -{ - float volume = 1.0; - - StreamDescriptor &streamDesc = mStreams[stream]; - - // Force max volume if stream cannot be muted - if (!streamDesc.mCanBeMuted) index = streamDesc.mIndexMax; - - int volInt = (100 * (index - streamDesc.mIndexMin)) / (streamDesc.mIndexMax - streamDesc.mIndexMin); - volume = AudioSystem::linearToLog(volInt); - - return volume; -} - -void AudioPolicyManagerGeneric::setStreamMute(int stream, bool on, audio_io_handle_t output) -{ - LOGV("setStreamMute() stream %d, mute %d, output %d", stream, on, output); - - StreamDescriptor &streamDesc = mStreams[stream]; - - if (on) { - if (streamDesc.mMuteCount++ == 0) { - if (streamDesc.mCanBeMuted) { - mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, 0, output); - } - } - } else { - if (streamDesc.mMuteCount == 0) { - LOGW("setStreamMute() unmuting non muted stream!"); - return; - } - if (--streamDesc.mMuteCount == 0) { - uint32_t device = mOutputs.valueFor(output)->mDevice; - float volume = computeVolume(stream, streamDesc.mIndexCur, device); - mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output); - } - } -} - -void AudioPolicyManagerGeneric::handleIncallSonification(int stream, bool starting) -{ - // if the stream pertains to sonification strategy and we are in call we must - // mute the stream if it is low visibility. If it is high visibility, we must play a tone - // in the device used for phone strategy and play the tone if the selected device does not - // interfere with the device used for phone strategy - if (getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) { - AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mHardwareOutput); - LOGV("handleIncallSonification() stream %d starting %d device %x", stream, starting, outputDesc->mDevice); - if (outputDesc->isUsedByStream((AudioSystem::stream_type)stream)) { - if (AudioSystem::isLowVisibility((AudioSystem::stream_type)stream)) { - LOGV("handleIncallSonification() low visibility"); - setStreamMute(stream, starting, mHardwareOutput); - } else { - if (starting) { - mpClientInterface->startTone(ToneGenerator::TONE_SUP_CALL_WAITING, AudioSystem::VOICE_CALL); - } else { - mpClientInterface->stopTone(); - } - } - } - } -} - - -// --- AudioOutputDescriptor class implementation - -AudioPolicyManagerGeneric::AudioOutputDescriptor::AudioOutputDescriptor() - : mSamplingRate(0), mFormat(0), mChannels(0), mLatency(0), - mFlags((AudioSystem::output_flags)0), mDevice(0) -{ - // clear usage count for all stream types - for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) { - mRefCount[i] = 0; - } -} - -uint32_t AudioPolicyManagerGeneric::AudioOutputDescriptor::device() -{ - return mDevice; -} - -void AudioPolicyManagerGeneric::AudioOutputDescriptor::changeRefCount(AudioSystem::stream_type stream, int delta) -{ - if ((delta + (int)mRefCount[stream]) < 0) { - LOGW("changeRefCount() invalid delta %d for stream %d, refCount %d", delta, stream, mRefCount[stream]); - mRefCount[stream] = 0; - return; - } - mRefCount[stream] += delta; - LOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]); -} - -uint32_t AudioPolicyManagerGeneric::AudioOutputDescriptor::refCount() -{ - uint32_t refcount = 0; - for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { - refcount += mRefCount[i]; - } - return refcount; -} - -status_t AudioPolicyManagerGeneric::AudioOutputDescriptor::dump(int fd) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - - snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate); - result.append(buffer); - snprintf(buffer, SIZE, " Format: %d\n", mFormat); - result.append(buffer); - snprintf(buffer, SIZE, " Channels: %08x\n", mChannels); - result.append(buffer); - snprintf(buffer, SIZE, " Latency: %d\n", mLatency); - result.append(buffer); - snprintf(buffer, SIZE, " Flags %08x\n", mFlags); - result.append(buffer); - snprintf(buffer, SIZE, " Devices %08x\n", mDevice); - result.append(buffer); - snprintf(buffer, SIZE, " Stream refCount\n"); - result.append(buffer); - for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) { - snprintf(buffer, SIZE, " %02d %d\n", i, mRefCount[i]); - result.append(buffer); - } - write(fd, result.string(), result.size()); - - return NO_ERROR; -} - -// --- AudioInputDescriptor class implementation - -AudioPolicyManagerGeneric::AudioInputDescriptor::AudioInputDescriptor() - : mSamplingRate(0), mFormat(0), mChannels(0), - mAcoustics((AudioSystem::audio_in_acoustics)0), mDevice(0), mRefCount(0) -{ -} - -status_t AudioPolicyManagerGeneric::AudioInputDescriptor::dump(int fd) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - - snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate); - result.append(buffer); - snprintf(buffer, SIZE, " Format: %d\n", mFormat); - result.append(buffer); - snprintf(buffer, SIZE, " Channels: %08x\n", mChannels); - result.append(buffer); - snprintf(buffer, SIZE, " Acoustics %08x\n", mAcoustics); - result.append(buffer); - snprintf(buffer, SIZE, " Devices %08x\n", mDevice); - result.append(buffer); - snprintf(buffer, SIZE, " Ref Count %d\n", mRefCount); - result.append(buffer); - write(fd, result.string(), result.size()); - - return NO_ERROR; -} - -// --- StreamDescriptor class implementation - -void AudioPolicyManagerGeneric::StreamDescriptor::dump(char* buffer, size_t size) -{ - snprintf(buffer, size, " %02d %02d %02d %02d %d\n", - mIndexMin, - mIndexMax, - mIndexCur, - mMuteCount, - mCanBeMuted); -} - -}; // namespace android diff --git a/libs/audioflinger/AudioPolicyManagerGeneric.h b/libs/audioflinger/AudioPolicyManagerGeneric.h deleted file mode 100644 index 4997cdf..0000000 --- a/libs/audioflinger/AudioPolicyManagerGeneric.h +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include <stdint.h> -#include <sys/types.h> - -#include <utils/Errors.h> -#include <utils/KeyedVector.h> -#include <hardware_legacy/AudioPolicyInterface.h> -#include <utils/threads.h> - - -namespace android { - -// ---------------------------------------------------------------------------- - -#define MAX_DEVICE_ADDRESS_LEN 20 -#define NUM_TEST_OUTPUTS 5 - -class AudioPolicyManagerGeneric: public AudioPolicyInterface -#ifdef AUDIO_POLICY_TEST - , public Thread -#endif //AUDIO_POLICY_TEST -{ - -public: - AudioPolicyManagerGeneric(AudioPolicyClientInterface *clientInterface); - virtual ~AudioPolicyManagerGeneric(); - - // AudioPolicyInterface - virtual status_t setDeviceConnectionState(AudioSystem::audio_devices device, - AudioSystem::device_connection_state state, - const char *device_address); - virtual AudioSystem::device_connection_state getDeviceConnectionState(AudioSystem::audio_devices device, - const char *device_address); - virtual void setPhoneState(int state); - virtual void setRingerMode(uint32_t mode, uint32_t mask); - virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config); - virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage); - virtual void setSystemProperty(const char* property, const char* value); - virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream, - uint32_t samplingRate, - uint32_t format, - uint32_t channels, - AudioSystem::output_flags flags); - virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream); - virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream); - virtual void releaseOutput(audio_io_handle_t output); - virtual audio_io_handle_t getInput(int inputSource, - uint32_t samplingRate, - uint32_t format, - uint32_t channels, - AudioSystem::audio_in_acoustics acoustics); - // indicates to the audio policy manager that the input starts being used. - virtual status_t startInput(audio_io_handle_t input); - // indicates to the audio policy manager that the input stops being used. - virtual status_t stopInput(audio_io_handle_t input); - virtual void releaseInput(audio_io_handle_t input); - virtual void initStreamVolume(AudioSystem::stream_type stream, - int indexMin, - int indexMax); - virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index); - virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index); - - virtual status_t dump(int fd); - -private: - - enum routing_strategy { - STRATEGY_MEDIA, - STRATEGY_PHONE, - STRATEGY_SONIFICATION, - STRATEGY_DTMF, - NUM_STRATEGIES - }; - - // descriptor for audio outputs. Used to maintain current configuration of each opened audio output - // and keep track of the usage of this output by each audio stream type. - class AudioOutputDescriptor - { - public: - AudioOutputDescriptor(); - - status_t dump(int fd); - - uint32_t device(); - void changeRefCount(AudioSystem::stream_type, int delta); - bool isUsedByStream(AudioSystem::stream_type stream) { return mRefCount[stream] > 0 ? true : false; } - uint32_t refCount(); - - uint32_t mSamplingRate; // - uint32_t mFormat; // - uint32_t mChannels; // output configuration - uint32_t mLatency; // - AudioSystem::output_flags mFlags; // - uint32_t mDevice; // current device this output is routed to - uint32_t mRefCount[AudioSystem::NUM_STREAM_TYPES]; // number of streams of each type using this output - }; - - // descriptor for audio inputs. Used to maintain current configuration of each opened audio input - // and keep track of the usage of this input. - class AudioInputDescriptor - { - public: - AudioInputDescriptor(); - - status_t dump(int fd); - - uint32_t mSamplingRate; // - uint32_t mFormat; // input configuration - uint32_t mChannels; // - AudioSystem::audio_in_acoustics mAcoustics; // - uint32_t mDevice; // current device this input is routed to - uint32_t mRefCount; // number of AudioRecord clients using this output - }; - - // stream descriptor used for volume control - class StreamDescriptor - { - public: - StreamDescriptor() - : mIndexMin(0), mIndexMax(1), mIndexCur(1), mMuteCount(0), mCanBeMuted(true) {} - - void dump(char* buffer, size_t size); - - int mIndexMin; // min volume index - int mIndexMax; // max volume index - int mIndexCur; // current volume index - int mMuteCount; // mute request counter - bool mCanBeMuted; // true is the stream can be muted - }; - - // return the strategy corresponding to a given stream type - static routing_strategy getStrategy(AudioSystem::stream_type stream); - // return the output handle of an output routed to the specified device, 0 if no output - // is routed to the device - float computeVolume(int stream, int index, uint32_t device); - // Mute or unmute the stream on the specified output - void setStreamMute(int stream, bool on, audio_io_handle_t output); - // handle special cases for sonification strategy while in call: mute streams or replace by - // a special tone in the device used for communication - void handleIncallSonification(int stream, bool starting); - - -#ifdef AUDIO_POLICY_TEST - virtual bool threadLoop(); - void exit(); - int testOutputIndex(audio_io_handle_t output); -#endif //AUDIO_POLICY_TEST - - - AudioPolicyClientInterface *mpClientInterface; // audio policy client interface - audio_io_handle_t mHardwareOutput; // hardware output handler - - KeyedVector<audio_io_handle_t, AudioOutputDescriptor *> mOutputs; // list ot output descritors - KeyedVector<audio_io_handle_t, AudioInputDescriptor *> mInputs; // list of input descriptors - uint32_t mAvailableOutputDevices; // bit field of all available output devices - uint32_t mAvailableInputDevices; // bit field of all available input devices - int mPhoneState; // current phone state - uint32_t mRingerMode; // current ringer mode - AudioSystem::forced_config mForceUse[AudioSystem::NUM_FORCE_USE]; // current forced use configuration - - StreamDescriptor mStreams[AudioSystem::NUM_STREAM_TYPES]; // stream descriptors for volume control - -#ifdef AUDIO_POLICY_TEST - Mutex mLock; - Condition mWaitWorkCV; - - int mCurOutput; - bool mDirectOutput; - audio_io_handle_t mTestOutputs[NUM_TEST_OUTPUTS]; - int mTestInput; - uint32_t mTestDevice; - uint32_t mTestSamplingRate; - uint32_t mTestFormat; - uint32_t mTestChannels; - uint32_t mTestLatencyMs; -#endif //AUDIO_POLICY_TEST - -}; - -}; diff --git a/libs/audioflinger/AudioPolicyService.cpp b/libs/audioflinger/AudioPolicyService.cpp index aa48019..bb3905c 100644 --- a/libs/audioflinger/AudioPolicyService.cpp +++ b/libs/audioflinger/AudioPolicyService.cpp @@ -30,9 +30,10 @@ #include <utils/String16.h> #include <utils/threads.h> #include "AudioPolicyService.h" -#include "AudioPolicyManagerGeneric.h" +#include <hardware_legacy/AudioPolicyManagerBase.h> #include <cutils/properties.h> #include <dlfcn.h> +#include <hardware_legacy/power.h> // ---------------------------------------------------------------------------- // the sim build doesn't have gettid @@ -43,8 +44,9 @@ namespace android { -static const char* kDeadlockedString = "AudioPolicyService may be deadlocked\n"; -static const char* kCmdDeadlockedString = "AudioPolicyService command thread may be deadlocked\n"; + +static const char *kDeadlockedString = "AudioPolicyService may be deadlocked\n"; +static const char *kCmdDeadlockedString = "AudioPolicyService command thread may be deadlocked\n"; static const int kDumpLockRetries = 50; static const int kDumpLockSleep = 20000; @@ -67,18 +69,18 @@ AudioPolicyService::AudioPolicyService() char value[PROPERTY_VALUE_MAX]; // start tone playback thread - mTonePlaybackThread = new AudioCommandThread(); + mTonePlaybackThread = new AudioCommandThread(String8("")); // start audio commands thread - mAudioCommandThread = new AudioCommandThread(); + mAudioCommandThread = new AudioCommandThread(String8("ApmCommandThread")); #if (defined GENERIC_AUDIO) || (defined AUDIO_POLICY_TEST) - mpPolicyManager = new AudioPolicyManagerGeneric(this); + mpPolicyManager = new AudioPolicyManagerBase(this); LOGV("build for GENERIC_AUDIO - using generic audio policy"); #else // if running in emulation - use the emulator driver if (property_get("ro.kernel.qemu", value, 0)) { LOGV("Running in emulation - using generic audio policy"); - mpPolicyManager = new AudioPolicyManagerGeneric(this); + mpPolicyManager = new AudioPolicyManagerBase(this); } else { LOGV("Using hardware specific audio policy"); @@ -556,8 +558,8 @@ status_t AudioPolicyService::setVoiceVolume(float volume, int delayMs) // ----------- AudioPolicyService::AudioCommandThread implementation ---------- -AudioPolicyService::AudioCommandThread::AudioCommandThread() - : Thread(false) +AudioPolicyService::AudioCommandThread::AudioCommandThread(String8 name) + : Thread(false), mName(name) { mpToneGenerator = NULL; } @@ -565,18 +567,20 @@ AudioPolicyService::AudioCommandThread::AudioCommandThread() AudioPolicyService::AudioCommandThread::~AudioCommandThread() { + if (mName != "" && !mAudioCommands.isEmpty()) { + release_wake_lock(mName.string()); + } mAudioCommands.clear(); if (mpToneGenerator != NULL) delete mpToneGenerator; } void AudioPolicyService::AudioCommandThread::onFirstRef() { - const size_t SIZE = 256; - char buffer[SIZE]; - - snprintf(buffer, SIZE, "AudioCommandThread"); - - run(buffer, ANDROID_PRIORITY_AUDIO); + if (mName != "") { + run(mName.string(), ANDROID_PRIORITY_AUDIO); + } else { + run("AudioCommandThread", ANDROID_PRIORITY_AUDIO); + } } bool AudioPolicyService::AudioCommandThread::threadLoop() @@ -657,6 +661,10 @@ bool AudioPolicyService::AudioCommandThread::threadLoop() break; } } + // release delayed commands wake lock + if (mName != "" && mAudioCommands.isEmpty()) { + release_wake_lock(mName.string()); + } LOGV("AudioCommandThread() going to sleep"); mWaitWorkCV.waitRelative(mLock, waitTime); LOGV("AudioCommandThread() waking up"); @@ -815,6 +823,11 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma command->mTime = systemTime() + milliseconds(delayMs); + // acquire wake lock to make sure delayed commands are processed + if (mName != "" && mAudioCommands.isEmpty()) { + acquire_wake_lock(PARTIAL_WAKE_LOCK, mName.string()); + } + // check same pending commands with later time stamps and eliminate them for (i = mAudioCommands.size()-1; i >= 0; i--) { AudioCommand *command2 = mAudioCommands[i]; @@ -883,7 +896,7 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma removedCommands.clear(); // insert command at the right place according to its time stamp - LOGV("inserting command: %d at index %ld, num commands %d", command->mCommand, i+1, mAudioCommands.size()); + LOGV("inserting command: %d at index %d, num commands %d", command->mCommand, (int)i+1, mAudioCommands.size()); mAudioCommands.insertAt(command, i + 1); } diff --git a/libs/audioflinger/AudioPolicyService.h b/libs/audioflinger/AudioPolicyService.h index b9234ec..a13d0bd 100644 --- a/libs/audioflinger/AudioPolicyService.h +++ b/libs/audioflinger/AudioPolicyService.h @@ -132,7 +132,7 @@ private: SET_VOICE_VOLUME }; - AudioCommandThread (); + AudioCommandThread (String8 name); virtual ~AudioCommandThread(); status_t dump(int fd); @@ -195,7 +195,8 @@ private: Condition mWaitWorkCV; Vector <AudioCommand *> mAudioCommands; // list of pending commands ToneGenerator *mpToneGenerator; // the tone generator - AudioCommand mLastCommand; + AudioCommand mLastCommand; // last processed command (used by dump) + String8 mName; // string used by wake lock fo delayed commands }; // Internal dump utilities. diff --git a/libs/audioflinger/AudioResampler.h b/libs/audioflinger/AudioResampler.h index 39656c0..2dfac76 100644 --- a/libs/audioflinger/AudioResampler.h +++ b/libs/audioflinger/AudioResampler.h @@ -76,8 +76,8 @@ protected: int32_t mInSampleRate; AudioBufferProvider::Buffer mBuffer; union { - int16_t mVolume[2]; - uint32_t mVolumeRL; + int16_t mVolume[2]; + uint32_t mVolumeRL; }; int16_t mTargetVolume[2]; format mFormat; diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index b2a7db8..0016503 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -292,6 +292,7 @@ static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER; static bool gHaveTLS = false; static pthread_key_t gTLS = 0; static bool gShutdown = false; +static bool gDisableBackgroundScheduling = false; IPCThreadState* IPCThreadState::self() { @@ -332,6 +333,11 @@ void IPCThreadState::shutdown() } } +void IPCThreadState::disableBackgroundScheduling(bool disable) +{ + gDisableBackgroundScheduling = disable; +} + sp<ProcessState> IPCThreadState::process() { return mProcess; @@ -386,6 +392,11 @@ void IPCThreadState::joinThreadPool(bool isMain) mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER); + // This thread may have been spawned by a thread that was in the background + // scheduling group, so first we will make sure it is in the default/foreground + // one to avoid performing an initial transaction in the background. + androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT); + status_t result; do { int32_t cmd; @@ -427,19 +438,13 @@ void IPCThreadState::joinThreadPool(bool isMain) } // After executing the command, ensure that the thread is returned to the - // default cgroup and priority before rejoining the pool. This is a failsafe - // in case the command implementation failed to properly restore the thread's - // scheduling parameters upon completion. - int my_id; -#ifdef HAVE_GETTID - my_id = gettid(); -#else - my_id = getpid(); -#endif - if (!set_sched_policy(my_id, SP_FOREGROUND)) { - // success; reset the priority as well - setpriority(PRIO_PROCESS, my_id, ANDROID_PRIORITY_NORMAL); - } + // default cgroup before rejoining the pool. The driver takes care of + // restoring the priority, but doesn't do anything with cgroups so we + // need to take care of that here in userspace. Note that we do make + // sure to go in the foreground after executing a transaction, but + // there are other callbacks into user code that could have changed + // our group so we want to make absolutely sure it is put back. + androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT); // Let this thread exit the thread pool if it is no longer // needed and it is not the main process thread. @@ -583,10 +588,10 @@ status_t IPCThreadState::clearDeathNotification(int32_t handle, BpBinder* proxy) } IPCThreadState::IPCThreadState() - : mProcess(ProcessState::self()) + : mProcess(ProcessState::self()), mMyThreadId(androidGetTid()) { pthread_setspecific(gTLS, this); - clearCaller(); + clearCaller(); mIn.setDataCapacity(256); mOut.setDataCapacity(256); } @@ -930,6 +935,27 @@ status_t IPCThreadState::executeCommand(int32_t cmd) mCallingPid = tr.sender_pid; mCallingUid = tr.sender_euid; + int curPrio = getpriority(PRIO_PROCESS, mMyThreadId); + if (gDisableBackgroundScheduling) { + if (curPrio > ANDROID_PRIORITY_NORMAL) { + // We have inherited a reduced priority from the caller, but do not + // want to run in that state in this process. The driver set our + // priority already (though not our scheduling class), so bounce + // it back to the default before invoking the transaction. + setpriority(PRIO_PROCESS, mMyThreadId, ANDROID_PRIORITY_NORMAL); + } + } else { + if (curPrio >= ANDROID_PRIORITY_BACKGROUND) { + // We want to use the inherited priority from the caller. + // Ensure this thread is in the background scheduling class, + // since the driver won't modify scheduling classes for us. + // The scheduling group is reset to default by the caller + // once this method returns after the transaction is complete. + androidSetThreadSchedulingGroup(mMyThreadId, + ANDROID_TGROUP_BG_NONINTERACT); + } + } + //LOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid); Parcel reply; @@ -966,7 +992,7 @@ status_t IPCThreadState::executeCommand(int32_t cmd) mCallingPid = origPid; mCallingUid = origUid; - + IF_LOG_TRANSACTIONS() { TextOutput::Bundle _b(alog); alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj " diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp index d5ffe7f..18669f7 100644 --- a/libs/binder/MemoryDealer.cpp +++ b/libs/binder/MemoryDealer.cpp @@ -17,12 +17,13 @@ #define LOG_TAG "MemoryDealer" #include <binder/MemoryDealer.h> +#include <binder/IPCThreadState.h> +#include <binder/MemoryBase.h> #include <utils/Log.h> -#include <binder/IPCThreadState.h> #include <utils/SortedVector.h> #include <utils/String8.h> -#include <binder/MemoryBase.h> +#include <utils/threads.h> #include <stdint.h> #include <stdio.h> @@ -40,90 +41,203 @@ namespace android { // ---------------------------------------------------------------------------- -HeapInterface::HeapInterface() { } -HeapInterface::~HeapInterface() { } +/* + * A simple templatized doubly linked-list implementation + */ + +template <typename NODE> +class LinkedList +{ + NODE* mFirst; + NODE* mLast; -// ---------------------------------------------------------------------------- +public: + LinkedList() : mFirst(0), mLast(0) { } + bool isEmpty() const { return mFirst == 0; } + NODE const* head() const { return mFirst; } + NODE* head() { return mFirst; } + NODE const* tail() const { return mLast; } + NODE* tail() { return mLast; } + + void insertAfter(NODE* node, NODE* newNode) { + newNode->prev = node; + newNode->next = node->next; + if (node->next == 0) mLast = newNode; + else node->next->prev = newNode; + node->next = newNode; + } -AllocatorInterface::AllocatorInterface() { } -AllocatorInterface::~AllocatorInterface() { } + void insertBefore(NODE* node, NODE* newNode) { + newNode->prev = node->prev; + newNode->next = node; + if (node->prev == 0) mFirst = newNode; + else node->prev->next = newNode; + node->prev = newNode; + } + + void insertHead(NODE* newNode) { + if (mFirst == 0) { + mFirst = mLast = newNode; + newNode->prev = newNode->next = 0; + } else { + newNode->prev = 0; + newNode->next = mFirst; + mFirst->prev = newNode; + mFirst = newNode; + } + } + + void insertTail(NODE* newNode) { + if (mLast == 0) { + insertHead(newNode); + } else { + newNode->prev = mLast; + newNode->next = 0; + mLast->next = newNode; + mLast = newNode; + } + } + + NODE* remove(NODE* node) { + if (node->prev == 0) mFirst = node->next; + else node->prev->next = node->next; + if (node->next == 0) mLast = node->prev; + else node->next->prev = node->prev; + return node; + } +}; // ---------------------------------------------------------------------------- -class SimpleMemory : public MemoryBase { +class Allocation : public MemoryBase { public: - SimpleMemory(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size); - virtual ~SimpleMemory(); + Allocation(const sp<MemoryDealer>& dealer, + const sp<IMemoryHeap>& heap, ssize_t offset, size_t size); + virtual ~Allocation(); +private: + sp<MemoryDealer> mDealer; }; +// ---------------------------------------------------------------------------- + +class SimpleBestFitAllocator +{ + enum { + PAGE_ALIGNED = 0x00000001 + }; +public: + SimpleBestFitAllocator(size_t size); + ~SimpleBestFitAllocator(); + + size_t allocate(size_t size, uint32_t flags = 0); + status_t deallocate(size_t offset); + size_t size() const; + void dump(const char* what) const; + void dump(String8& res, const char* what) const; + +private: + + struct chunk_t { + chunk_t(size_t start, size_t size) + : start(start), size(size), free(1), prev(0), next(0) { + } + size_t start; + size_t size : 28; + int free : 4; + mutable chunk_t* prev; + mutable chunk_t* next; + }; + + ssize_t alloc(size_t size, uint32_t flags); + chunk_t* dealloc(size_t start); + void dump_l(const char* what) const; + void dump_l(String8& res, const char* what) const; + + static const int kMemoryAlign; + mutable Mutex mLock; + LinkedList<chunk_t> mList; + size_t mHeapSize; +}; // ---------------------------------------------------------------------------- -MemoryDealer::Allocation::Allocation( - const sp<MemoryDealer>& dealer, ssize_t offset, size_t size, - const sp<IMemory>& memory) - : mDealer(dealer), mOffset(offset), mSize(size), mMemory(memory) +Allocation::Allocation( + const sp<MemoryDealer>& dealer, + const sp<IMemoryHeap>& heap, ssize_t offset, size_t size) + : MemoryBase(heap, offset, size), mDealer(dealer) { +#ifndef NDEBUG + void* const start_ptr = (void*)(intptr_t(heap->base()) + offset); + memset(start_ptr, 0xda, size); +#endif } -MemoryDealer::Allocation::~Allocation() +Allocation::~Allocation() { - if (mSize) { + size_t freedOffset = getOffset(); + size_t freedSize = getSize(); + if (freedSize) { /* NOTE: it's VERY important to not free allocations of size 0 because * they're special as they don't have any record in the allocator * and could alias some real allocation (their offset is zero). */ - mDealer->deallocate(mOffset); - } -} + mDealer->deallocate(freedOffset); + + // keep the size to unmap in excess + size_t pagesize = getpagesize(); + size_t start = freedOffset; + size_t end = start + freedSize; + start &= ~(pagesize-1); + end = (end + pagesize-1) & ~(pagesize-1); + + // give back to the kernel the pages we don't need + size_t free_start = freedOffset; + size_t free_end = free_start + freedSize; + if (start < free_start) + start = free_start; + if (end > free_end) + end = free_end; + start = (start + pagesize-1) & ~(pagesize-1); + end &= ~(pagesize-1); + + if (start < end) { + void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + start); + size_t size = end-start; -sp<IMemoryHeap> MemoryDealer::Allocation::getMemory( - ssize_t* offset, size_t* size) const -{ - return mMemory->getMemory(offset, size); +#ifndef NDEBUG + memset(start_ptr, 0xdf, size); +#endif + + // 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"); + } +#endif + } + } } // ---------------------------------------------------------------------------- -MemoryDealer::MemoryDealer(size_t size, uint32_t flags, const char* name) - : mHeap(new SharedHeap(size, flags, name)), +MemoryDealer::MemoryDealer(size_t size, const char* name) + : mHeap(new MemoryHeapBase(size, 0, name)), mAllocator(new SimpleBestFitAllocator(size)) { } -MemoryDealer::MemoryDealer(const sp<HeapInterface>& heap) - : mHeap(heap), - mAllocator(new SimpleBestFitAllocator(heap->virtualSize())) -{ -} - -MemoryDealer::MemoryDealer( const sp<HeapInterface>& heap, - const sp<AllocatorInterface>& allocator) - : mHeap(heap), mAllocator(allocator) -{ -} - MemoryDealer::~MemoryDealer() { + delete mAllocator; } -sp<IMemory> MemoryDealer::allocate(size_t size, uint32_t flags) +sp<IMemory> MemoryDealer::allocate(size_t size) { sp<IMemory> memory; - const ssize_t offset = allocator()->allocate(size, flags); + const ssize_t offset = allocator()->allocate(size); if (offset >= 0) { - sp<IMemory> new_memory = heap()->mapMemory(offset, size); - if (new_memory != 0) { - memory = new Allocation(this, offset, size, new_memory); - } else { - LOGE("couldn't map [%8lx, %u]", offset, size); - if (size) { - /* NOTE: it's VERY important to not free allocations of size 0 - * because they're special as they don't have any record in the - * allocator and could alias some real allocation - * (their offset is zero). */ - allocator()->deallocate(offset); - } - } + memory = new Allocation(this, heap(), offset, size); } return memory; } @@ -133,16 +247,16 @@ void MemoryDealer::deallocate(size_t offset) allocator()->deallocate(offset); } -void MemoryDealer::dump(const char* what, uint32_t flags) const +void MemoryDealer::dump(const char* what) const { - allocator()->dump(what, flags); + allocator()->dump(what); } -const sp<HeapInterface>& MemoryDealer::heap() const { +const sp<IMemoryHeap>& MemoryDealer::heap() const { return mHeap; } -const sp<AllocatorInterface>& MemoryDealer::allocator() const { +SimpleBestFitAllocator* MemoryDealer::allocator() const { return mAllocator; } @@ -287,28 +401,28 @@ SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start) return 0; } -void SimpleBestFitAllocator::dump(const char* what, uint32_t flags) const +void SimpleBestFitAllocator::dump(const char* what) const { Mutex::Autolock _l(mLock); - dump_l(what, flags); + dump_l(what); } -void SimpleBestFitAllocator::dump_l(const char* what, uint32_t flags) const +void SimpleBestFitAllocator::dump_l(const char* what) const { String8 result; - dump_l(result, what, flags); + dump_l(result, what); LOGD("%s", result.string()); } void SimpleBestFitAllocator::dump(String8& result, - const char* what, uint32_t flags) const + const char* what) const { Mutex::Autolock _l(mLock); - dump_l(result, what, flags); + dump_l(result, what); } void SimpleBestFitAllocator::dump_l(String8& result, - const char* what, uint32_t flags) const + const char* what) const { size_t size = 0; int32_t i = 0; @@ -341,81 +455,10 @@ void SimpleBestFitAllocator::dump_l(String8& result, i++; cur = cur->next; } - snprintf(buffer, SIZE, " size allocated: %u (%u KB)\n", int(size), int(size/1024)); + snprintf(buffer, SIZE, + " size allocated: %u (%u KB)\n", int(size), int(size/1024)); result.append(buffer); } - -// ---------------------------------------------------------------------------- - -SharedHeap::SharedHeap() - : HeapInterface(), MemoryHeapBase() -{ -} -SharedHeap::SharedHeap(size_t size, uint32_t flags, char const * name) - : MemoryHeapBase(size, flags, name) -{ -} - -SharedHeap::~SharedHeap() -{ -} - -sp<IMemory> SharedHeap::mapMemory(size_t offset, size_t size) -{ - return new SimpleMemory(this, offset, size); -} - - -SimpleMemory::SimpleMemory(const sp<IMemoryHeap>& heap, - ssize_t offset, size_t size) - : MemoryBase(heap, offset, size) -{ -#ifndef NDEBUG - void* const start_ptr = (void*)(intptr_t(heap->base()) + offset); - memset(start_ptr, 0xda, size); -#endif -} - -SimpleMemory::~SimpleMemory() -{ - size_t freedOffset = getOffset(); - size_t freedSize = getSize(); - - // keep the size to unmap in excess - size_t pagesize = getpagesize(); - size_t start = freedOffset; - size_t end = start + freedSize; - start &= ~(pagesize-1); - end = (end + pagesize-1) & ~(pagesize-1); - - // give back to the kernel the pages we don't need - size_t free_start = freedOffset; - size_t free_end = free_start + freedSize; - if (start < free_start) - start = free_start; - if (end > free_end) - end = free_end; - start = (start + pagesize-1) & ~(pagesize-1); - end &= ~(pagesize-1); - - 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); -#endif - - // 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"); - } -#endif - } -} }; // namespace android diff --git a/libs/binder/MemoryHeapPmem.cpp b/libs/binder/MemoryHeapPmem.cpp index c660947..16e92f9 100644 --- a/libs/binder/MemoryHeapPmem.cpp +++ b/libs/binder/MemoryHeapPmem.cpp @@ -127,7 +127,7 @@ void SubRegionMemory::revoke() MemoryHeapPmem::MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap, uint32_t flags) - : HeapInterface(), MemoryHeapBase() + : MemoryHeapBase() { char const * const device = pmemHeap->getDevice(); #if HAVE_ANDROID_OS diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index e397bce..00d2210 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -28,6 +28,7 @@ #include <utils/String16.h> #include <utils/TextOutput.h> #include <utils/misc.h> +#include <utils/Flattenable.h> #include <private/binder/binder_module.h> @@ -675,6 +676,42 @@ status_t Parcel::writeDupFileDescriptor(int fd) return writeObject(obj, true); } +status_t Parcel::write(const Flattenable& val) +{ + status_t err; + + // size if needed + size_t len = val.getFlattenedSize(); + size_t fd_count = val.getFdCount(); + + err = this->writeInt32(len); + if (err) return err; + + err = this->writeInt32(fd_count); + if (err) return err; + + // payload + void* buf = this->writeInplace(PAD_SIZE(len)); + if (buf == NULL) + return BAD_VALUE; + + int* fds = NULL; + if (fd_count) { + fds = new int[fd_count]; + } + + err = val.flatten(buf, len, fds, fd_count); + for (size_t i=0 ; i<fd_count && err==NO_ERROR ; i++) { + err = this->writeDupFileDescriptor( fds[i] ); + } + + if (fd_count) { + delete [] fds; + } + + return err; +} + status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData) { const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity; @@ -713,7 +750,6 @@ restart_write: goto restart_write; } - void Parcel::remove(size_t start, size_t amt) { LOG_ALWAYS_FATAL("Parcel::remove() not yet implemented!"); @@ -940,6 +976,38 @@ int Parcel::readFileDescriptor() const return BAD_TYPE; } +status_t Parcel::read(Flattenable& val) const +{ + // size + const size_t len = this->readInt32(); + const size_t fd_count = this->readInt32(); + + // payload + void const* buf = this->readInplace(PAD_SIZE(len)); + if (buf == NULL) + return BAD_VALUE; + + int* fds = NULL; + if (fd_count) { + fds = new int[fd_count]; + } + + status_t err = NO_ERROR; + for (size_t i=0 ; i<fd_count && err==NO_ERROR ; i++) { + fds[i] = dup(this->readFileDescriptor()); + if (fds[i] < 0) err = BAD_VALUE; + } + + if (err == NO_ERROR) { + err = val.unflatten(buf, len, fds, fd_count); + } + + if (fd_count) { + delete [] fds; + } + + return err; +} const flat_binder_object* Parcel::readObject(bool nullMetaData) const { const size_t DPOS = mDataPos; diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk index b3fed58..86eb78d 100644 --- a/libs/surfaceflinger/Android.mk +++ b/libs/surfaceflinger/Android.mk @@ -35,11 +35,11 @@ LOCAL_SHARED_LIBRARIES := \ libpixelflinger \ libhardware \ libutils \ - libskia \ libEGL \ libGLESv1_CM \ libbinder \ - libui + libui \ + libsurfaceflinger_client LOCAL_C_INCLUDES := \ $(call include-path-for, corecg graphics) diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp index d9d9bfe..5969617 100644 --- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp +++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp @@ -246,10 +246,15 @@ void DisplayHardware::init(uint32_t dpy) LOGI("version : %s", glGetString(GL_VERSION)); LOGI("extensions: %s", gl_extensions); - if (strstr(gl_renderer, "Adreno")) { +#if 0 + // for drivers that don't have proper support for flushing cached buffers + // on gralloc unlock, uncomment this block and test for the specific + // renderer substring + if (strstr(gl_renderer, "<some vendor string>")) { LOGD("Assuming uncached graphics buffers."); mFlags &= ~CACHED_BUFFERS; } +#endif if (strstr(gl_extensions, "GL_ARB_texture_non_power_of_two")) { mFlags |= NPOT_EXTENSION; diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp index 1870d3a..4dc4a15 100644 --- a/libs/surfaceflinger/Layer.cpp +++ b/libs/surfaceflinger/Layer.cpp @@ -27,7 +27,8 @@ #include <ui/GraphicBuffer.h> #include <ui/PixelFormat.h> -#include <ui/Surface.h> + +#include <surfaceflinger/Surface.h> #include "clz.h" #include "Layer.h" @@ -155,7 +156,11 @@ void Layer::reloadTexture(const Region& dirty) if (mFlags & DisplayHardware::DIRECT_TEXTURE) { if (buffer->usage & GraphicBuffer::USAGE_HW_TEXTURE) { if (mTextures[index].dirty) { - initializeEglImage(buffer, &mTextures[index]); + if (initializeEglImage(buffer, &mTextures[index]) != NO_ERROR) { + // not sure what we can do here... + mFlags &= ~DisplayHardware::DIRECT_TEXTURE; + goto slowpath; + } } } else { if (mHybridBuffer==0 || (mHybridBuffer->width != buffer->width || @@ -165,8 +170,13 @@ void Layer::reloadTexture(const Region& dirty) buffer->width, buffer->height, buffer->format, GraphicBuffer::USAGE_SW_WRITE_OFTEN | GraphicBuffer::USAGE_HW_TEXTURE); - initializeEglImage( - mHybridBuffer, &mTextures[0]); + if (initializeEglImage( + mHybridBuffer, &mTextures[0]) != NO_ERROR) { + // not sure what we can do here... + mFlags &= ~DisplayHardware::DIRECT_TEXTURE; + mHybridBuffer.clear(); + goto slowpath; + } } GGLSurface t; @@ -184,20 +194,20 @@ void Layer::reloadTexture(const Region& dirty) if (res == NO_ERROR) { int bpp = 0; switch (t.format) { - case GGL_PIXEL_FORMAT_RGB_565: - case GGL_PIXEL_FORMAT_RGBA_4444: + case HAL_PIXEL_FORMAT_RGB_565: + case HAL_PIXEL_FORMAT_RGBA_4444: bpp = 2; break; - case GGL_PIXEL_FORMAT_RGBA_8888: - case GGL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: bpp = 4; break; - case GGL_PIXEL_FORMAT_YCbCr_422_SP: - case GGL_PIXEL_FORMAT_YCbCr_420_SP: - // just show the Y plane of YUV buffers - bpp = 1; - break; default: + if (isSupportedYuvFormat(t.format)) { + // just show the Y plane of YUV buffers + bpp = 1; + break; + } // oops, we don't handle this format! LOGE("layer %p, texture=%d, using format %d, which is not " "supported by the GL", this, texture->name, t.format); @@ -235,6 +245,7 @@ void Layer::reloadTexture(const Region& dirty) } else #endif { +slowpath: for (size_t i=0 ; i<NUM_BUFFERS ; i++) { mTextures[i].image = EGL_NO_IMAGE_KHR; } @@ -454,44 +465,61 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) // for composition later in the loop return; } - + + // ouch, this really should never happen + if (uint32_t(buf)>=NUM_BUFFERS) { + LOGE("retireAndLock() buffer index (%d) out of range", buf); + mPostedDirtyRegion.clear(); + return; + } + // we retired a buffer, which becomes the new front buffer mFrontBufferIndex = buf; // get the dirty region sp<GraphicBuffer> newFrontBuffer(getBuffer(buf)); - const Region dirty(lcblk->getDirtyRegion(buf)); - mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() ); - - const Layer::State& front(drawingState()); - if (newFrontBuffer->getWidth() == front.requested_w && - newFrontBuffer->getHeight() == front.requested_h) - { - if ((front.w != front.requested_w) || - (front.h != front.requested_h)) + if (newFrontBuffer != NULL) { + // compute the posted region + const Region dirty(lcblk->getDirtyRegion(buf)); + mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() ); + + // update the layer size and release freeze-lock + const Layer::State& front(drawingState()); + if (newFrontBuffer->getWidth() == front.requested_w && + newFrontBuffer->getHeight() == front.requested_h) { - // Here we pretend the transaction happened by updating the - // current and drawing states. Drawing state is only accessed - // in this thread, no need to have it locked - Layer::State& editDraw(mDrawingState); - editDraw.w = editDraw.requested_w; - editDraw.h = editDraw.requested_h; - - // We also need to update the current state so that we don't - // end-up doing too much work during the next transaction. - // NOTE: We actually don't need hold the transaction lock here - // because State::w and State::h are only accessed from - // this thread - Layer::State& editTemp(currentState()); - editTemp.w = editDraw.w; - editTemp.h = editDraw.h; - - // recompute visible region - recomputeVisibleRegions = true; - } + if ((front.w != front.requested_w) || + (front.h != front.requested_h)) + { + // Here we pretend the transaction happened by updating the + // current and drawing states. Drawing state is only accessed + // in this thread, no need to have it locked + Layer::State& editDraw(mDrawingState); + editDraw.w = editDraw.requested_w; + editDraw.h = editDraw.requested_h; + + // We also need to update the current state so that we don't + // end-up doing too much work during the next transaction. + // NOTE: We actually don't need hold the transaction lock here + // because State::w and State::h are only accessed from + // this thread + Layer::State& editTemp(currentState()); + editTemp.w = editDraw.w; + editTemp.h = editDraw.h; + + // recompute visible region + recomputeVisibleRegions = true; + } - // we now have the correct size, unfreeze the screen - mFreezeLock.clear(); + // we now have the correct size, unfreeze the screen + mFreezeLock.clear(); + } + } else { + // this should not happen unless we ran out of memory while + // allocating the buffer. we're hoping that things will get back + // to normal the next time the app tries to draw into this buffer. + // meanwhile, pretend the screen didn't update. + mPostedDirtyRegion.clear(); } if (lcblk->getQueuedCount()) { diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h index 1310ecc..743afb4 100644 --- a/libs/surfaceflinger/Layer.h +++ b/libs/surfaceflinger/Layer.h @@ -78,6 +78,8 @@ public: inline const sp<FreezeLock>& getFreezeLock() const { return mFreezeLock; } // only for debugging inline PixelFormat pixelFormat() const { return mFormat; } + // only for debugging + inline int getFrontBufferIndex() const { return mFrontBufferIndex; } private: inline sp<GraphicBuffer> getFrontBufferLocked() { diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp index 8003d22..efbc77a 100644 --- a/libs/surfaceflinger/LayerBase.cpp +++ b/libs/surfaceflinger/LayerBase.cpp @@ -52,8 +52,9 @@ LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display) mTransformed(false), mUseLinearFiltering(false), mOrientation(0), + mLeft(0), mTop(0), mTransactionFlags(0), - mPremultipliedAlpha(true), + mPremultipliedAlpha(true), mDebug(false), mInvalidate(0) { const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware()); @@ -64,6 +65,14 @@ LayerBase::~LayerBase() { } +void LayerBase::setName(const String8& name) { + mName = name; +} + +String8 LayerBase::getName() const { + return mName; +} + const GraphicPlane& LayerBase::graphicPlane(int dpy) const { return mFlinger->graphicPlane(dpy); @@ -205,7 +214,6 @@ uint32_t LayerBase::doTransaction(uint32_t flags) if ((front.w != temp.w) || (front.h != temp.h)) { // invalidate and recompute the visible regions if needed flags |= Layer::eVisibleRegion; - this->contentDirty = true; } if (temp.sequence != front.sequence) { @@ -444,12 +452,21 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const glLoadIdentity(); // the texture's source is rotated - if (texture.transform == HAL_TRANSFORM_ROT_90) { - // TODO: handle the other orientations - glTranslatef(0, 1, 0); - glRotatef(-90, 0, 0, 1); + switch (texture.transform) { + case HAL_TRANSFORM_ROT_90: + glTranslatef(0, 1, 0); + glRotatef(-90, 0, 0, 1); + break; + case HAL_TRANSFORM_ROT_180: + glTranslatef(1, 1, 0); + glRotatef(-180, 0, 0, 1); + break; + case HAL_TRANSFORM_ROT_270: + glTranslatef(1, 0, 0); + glRotatef(-270, 0, 0, 1); + break; } - + if (texture.NPOTAdjust) { glScalef(texture.wScale, texture.hScale, 1.0f); } @@ -500,6 +517,21 @@ void LayerBase::validateTexture(GLint textureName) const } } +bool LayerBase::isSupportedYuvFormat(int format) const +{ + switch (format) { + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_YCbCr_422_P: + case HAL_PIXEL_FORMAT_YCbCr_420_P: + case HAL_PIXEL_FORMAT_YCbCr_422_I: + case HAL_PIXEL_FORMAT_YCbCr_420_I: + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + return true; + } + return false; +} + void LayerBase::loadTexture(Texture* texture, const Region& dirty, const GGLSurface& t) const { @@ -564,21 +596,20 @@ void LayerBase::loadTexture(Texture* texture, data = t.data; } - if (t.format == GGL_PIXEL_FORMAT_RGB_565) { + if (t.format == HAL_PIXEL_FORMAT_RGB_565) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texture->potWidth, texture->potHeight, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data); - } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) { + } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->potWidth, texture->potHeight, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data); - } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888 || - t.format == GGL_PIXEL_FORMAT_RGBX_8888) { + } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 || + t.format == HAL_PIXEL_FORMAT_RGBX_8888) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->potWidth, texture->potHeight, 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) { + } else if (isSupportedYuvFormat(t.format)) { // just show the Y plane of YUV buffers glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, texture->potWidth, texture->potHeight, 0, @@ -590,24 +621,23 @@ void LayerBase::loadTexture(Texture* texture, } } if (!data) { - if (t.format == GGL_PIXEL_FORMAT_RGB_565) { + if (t.format == HAL_PIXEL_FORMAT_RGB_565) { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, bounds.top, t.width, bounds.height(), GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t.data + bounds.top*t.stride*2); - } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) { + } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, bounds.top, t.width, bounds.height(), GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t.data + bounds.top*t.stride*2); - } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888 || - t.format == GGL_PIXEL_FORMAT_RGBX_8888) { + } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 || + t.format == HAL_PIXEL_FORMAT_RGBX_8888) { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, bounds.top, t.width, bounds.height(), GL_RGBA, GL_UNSIGNED_BYTE, t.data + bounds.top*t.stride*4); - } else if ( t.format == GGL_PIXEL_FORMAT_YCbCr_422_SP || - t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) { + } else if (isSupportedYuvFormat(t.format)) { // just show the Y plane of YUV buffers glTexSubImage2D(GL_TEXTURE_2D, 0, 0, bounds.top, t.width, bounds.height(), @@ -643,22 +673,15 @@ status_t LayerBase::initializeEglImage( dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, (EGLClientBuffer)clientBuf, attrs); - LOGE_IF(texture->image == EGL_NO_IMAGE_KHR, - "eglCreateImageKHR() failed. err=0x%4x", - eglGetError()); - if (texture->image != EGL_NO_IMAGE_KHR) { glBindTexture(GL_TEXTURE_2D, texture->name); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)texture->image); GLint error = glGetError(); if (UNLIKELY(error != GL_NO_ERROR)) { - // this failed, for instance, because we don't support NPOT. - // FIXME: do something! LOGE("layer=%p, glEGLImageTargetTexture2DOES(%p) " "failed err=0x%04x", this, texture->image, error); - mFlags &= ~DisplayHardware::DIRECT_TEXTURE; err = INVALID_OPERATION; } else { // Everything went okay! @@ -668,6 +691,8 @@ status_t LayerBase::initializeEglImage( texture->height = clientBuf->height; } } else { + LOGE("layer=%p, eglCreateImageKHR() failed. err=0x%4x", + this, eglGetError()); err = INVALID_OPERATION; } return err; @@ -680,8 +705,8 @@ int32_t LayerBaseClient::sIdentity = 0; LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display, const sp<Client>& client, int32_t i) - : LayerBase(flinger, display), lcblk(NULL), client(client), - mIndex(i), mIdentity(uint32_t(android_atomic_inc(&sIdentity))) + : LayerBase(flinger, display), lcblk(NULL), client(client), mIndex(i), + mIdentity(uint32_t(android_atomic_inc(&sIdentity))) { lcblk = new SharedBufferServer( client->ctrlblk, i, NUM_BUFFERS, @@ -809,7 +834,7 @@ void LayerBaseClient::Surface::unregisterBuffers() } sp<OverlayRef> LayerBaseClient::Surface::createOverlay( - uint32_t w, uint32_t h, int32_t format) + uint32_t w, uint32_t h, int32_t format, int32_t orientation) { return NULL; }; diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h index ed07b3f..62ec839 100644 --- a/libs/surfaceflinger/LayerBase.h +++ b/libs/surfaceflinger/LayerBase.h @@ -22,15 +22,17 @@ #include <EGL/egl.h> #include <EGL/eglext.h> - -#include <private/ui/SharedBufferStack.h> -#include <private/ui/LayerState.h> +#include <GLES/gl.h> #include <utils/RefBase.h> #include <ui/Region.h> #include <ui/Overlay.h> +#include <surfaceflinger/ISurfaceFlingerClient.h> +#include <private/surfaceflinger/SharedBufferStack.h> +#include <private/surfaceflinger/LayerState.h> + #include <pixelflinger/pixelflinger.h> #include "Transform.h" @@ -99,6 +101,9 @@ public: Region transparentRegion; }; + void setName(const String8& name); + String8 getName() const; + // modify current state bool setPosition(int32_t x, int32_t y); bool setLayer(uint32_t z); @@ -119,7 +124,7 @@ public: void drawRegion(const Region& reg) const; void invalidate(); - + /** * draw - performs some global clipping optimizations * and calls onDraw(). @@ -152,11 +157,11 @@ public: /** * setCoveredRegion - called when the covered region changes. The covered - * region correspond to any area of the surface that is covered + * region corresponds to any area of the surface that is covered * (transparently or not) by another surface. */ virtual void setCoveredRegion(const Region& coveredRegion); - + /** * validateVisibility - cache a bunch of things */ @@ -264,6 +269,7 @@ protected: status_t initializeEglImage( const sp<GraphicBuffer>& buffer, Texture* texture); + bool isSupportedYuvFormat(int format) const; sp<SurfaceFlinger> mFlinger; uint32_t mFlags; @@ -284,6 +290,9 @@ protected: // don't change, don't need a lock bool mPremultipliedAlpha; + String8 mName; + mutable bool mDebug; + // atomic volatile int32_t mInvalidate; @@ -330,6 +339,7 @@ public: virtual void onRemoved(); + class Surface : public BnSurface { public: @@ -351,7 +361,7 @@ public: virtual void postBuffer(ssize_t offset); virtual void unregisterBuffers(); virtual sp<OverlayRef> createOverlay(uint32_t w, uint32_t h, - int32_t format); + int32_t format, int32_t orientation); protected: friend class LayerBaseClient; diff --git a/libs/surfaceflinger/LayerBlur.h b/libs/surfaceflinger/LayerBlur.h index 2e9d7c6..5b63dec 100644 --- a/libs/surfaceflinger/LayerBlur.h +++ b/libs/surfaceflinger/LayerBlur.h @@ -20,8 +20,6 @@ #include <stdint.h> #include <sys/types.h> -#include <private/ui/LayerState.h> - #include <ui/Region.h> #include "LayerBase.h" diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp index 2ff6167..5c21593 100644 --- a/libs/surfaceflinger/LayerBuffer.cpp +++ b/libs/surfaceflinger/LayerBuffer.cpp @@ -182,14 +182,15 @@ status_t LayerBuffer::registerBuffers(const ISurface::BufferHeap& buffers) /** * This creates an "overlay" source for this surface */ -sp<OverlayRef> LayerBuffer::createOverlay(uint32_t w, uint32_t h, int32_t f) +sp<OverlayRef> LayerBuffer::createOverlay(uint32_t w, uint32_t h, int32_t f, + int32_t orientation) { sp<OverlayRef> result; Mutex::Autolock _l(mLock); if (mSource != 0) return result; - sp<OverlaySource> source = new OverlaySource(*this, &result, w, h, f); + sp<OverlaySource> source = new OverlaySource(*this, &result, w, h, f, orientation); if (result != 0) { mSource = source; } @@ -248,11 +249,11 @@ void LayerBuffer::SurfaceLayerBuffer::unregisterBuffers() } sp<OverlayRef> LayerBuffer::SurfaceLayerBuffer::createOverlay( - uint32_t w, uint32_t h, int32_t format) { + uint32_t w, uint32_t h, int32_t format, int32_t orientation) { sp<OverlayRef> result; sp<LayerBuffer> owner(getOwner()); if (owner != 0) - result = owner->createOverlay(w, h, format); + result = owner->createOverlay(w, h, format, orientation); return result; } @@ -260,8 +261,9 @@ sp<OverlayRef> LayerBuffer::SurfaceLayerBuffer::createOverlay( // LayerBuffer::Buffer // ============================================================================ -LayerBuffer::Buffer::Buffer(const ISurface::BufferHeap& buffers, ssize_t offset) - : mBufferHeap(buffers) +LayerBuffer::Buffer::Buffer(const ISurface::BufferHeap& buffers, + ssize_t offset, size_t bufferSize) + : mBufferHeap(buffers), mSupportsCopybit(false) { NativeBuffer& src(mNativeBuffer); src.crop.l = 0; @@ -279,14 +281,12 @@ LayerBuffer::Buffer::Buffer(const ISurface::BufferHeap& buffers, ssize_t offset) if (module && module->perform) { int err = module->perform(module, GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER, - buffers.heap->heapID(), buffers.heap->getSize(), + buffers.heap->heapID(), bufferSize, offset, buffers.heap->base(), &src.img.handle); - LOGE_IF(err, "CREATE_HANDLE_FROM_BUFFER (heapId=%d, size=%d, " - "offset=%ld, base=%p) failed (%s)", - buffers.heap->heapID(), buffers.heap->getSize(), - offset, buffers.heap->base(), strerror(-err)); + // we can fail here is the passed buffer is purely software + mSupportsCopybit = (err == NO_ERROR); } } @@ -329,7 +329,8 @@ bool LayerBuffer::Source::transformed() const { LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer, const ISurface::BufferHeap& buffers) - : Source(layer), mStatus(NO_ERROR), mBufferSize(0) + : Source(layer), mStatus(NO_ERROR), mBufferSize(0), + mUseEGLImageDirectly(true) { if (buffers.heap == NULL) { // this is allowed, but in this case, it is illegal to receive @@ -372,8 +373,23 @@ LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer, LayerBuffer::BufferSource::~BufferSource() { + class MessageDestroyTexture : public MessageBase { + SurfaceFlinger* flinger; + GLuint name; + public: + MessageDestroyTexture( + SurfaceFlinger* flinger, GLuint name) + : flinger(flinger), name(name) { } + virtual bool handler() { + glDeleteTextures(1, &name); + return true; + } + }; + if (mTexture.name != -1U) { - glDeleteTextures(1, &mTexture.name); + // GL textures can only be destroyed from the GL thread + mLayer.mFlinger->mEventQueue.postMessage( + new MessageDestroyTexture(mLayer.mFlinger.get(), mTexture.name) ); } if (mTexture.image != EGL_NO_IMAGE_KHR) { EGLDisplay dpy(mLayer.mFlinger->graphicPlane(0).getEGLDisplay()); @@ -400,7 +416,7 @@ void LayerBuffer::BufferSource::postBuffer(ssize_t offset) sp<Buffer> buffer; if (buffers.heap != 0) { - buffer = new LayerBuffer::Buffer(buffers, offset); + buffer = new LayerBuffer::Buffer(buffers, offset, mBufferSize); if (buffer->getStatus() != NO_ERROR) buffer.clear(); setBuffer(buffer); @@ -452,23 +468,47 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const #if defined(EGL_ANDROID_image_native_buffer) if (mLayer.mFlags & DisplayHardware::DIRECT_TEXTURE) { - copybit_device_t* copybit = mLayer.mBlitEngine; - if (copybit) { - // create our EGLImageKHR the first time - err = initTempBuffer(); - if (err == NO_ERROR) { + err = INVALID_OPERATION; + if (ourBuffer->supportsCopybit()) { + + // there are constraints on buffers used by the GPU and these may not + // be honored here. We need to change the API so the buffers + // are allocated with gralloc. For now disable this code-path +#if 0 + // First, try to use the buffer as an EGLImage directly + if (mUseEGLImageDirectly) { // NOTE: Assume the buffer is allocated with the proper USAGE flags - const NativeBuffer& dst(mTempBuffer); - region_iterator clip(Region(Rect(dst.crop.r, dst.crop.b))); - copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0); - copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF); - copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE); - err = copybit->stretch(copybit, &dst.img, &src.img, - &dst.crop, &src.crop, &clip); + sp<GraphicBuffer> buffer = new GraphicBuffer( + src.img.w, src.img.h, src.img.format, + GraphicBuffer::USAGE_HW_TEXTURE, + src.img.w, src.img.handle, false); + + err = mLayer.initializeEglImage(buffer, &mTexture); + if (err != NO_ERROR) { + mUseEGLImageDirectly = false; + } + } +#endif + + copybit_device_t* copybit = mLayer.mBlitEngine; + if (copybit && err != NO_ERROR) { + // create our EGLImageKHR the first time + err = initTempBuffer(); + if (err == NO_ERROR) { + // NOTE: Assume the buffer is allocated with the proper USAGE flags + const NativeBuffer& dst(mTempBuffer); + region_iterator clip(Region(Rect(dst.crop.r, dst.crop.b))); + copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0); + copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF); + copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE); + err = copybit->stretch(copybit, &dst.img, &src.img, + &dst.crop, &src.crop, &clip); + if (err != NO_ERROR) { + clearTempBufferImage(); + } + } } - } else { - err = INVALID_OPERATION; } } #endif @@ -504,16 +544,21 @@ status_t LayerBuffer::BufferSource::initTempBuffer() const int t = w; w = h; h = t; } + // we're in the copybit case, so make sure we can handle this blit + // we don't have to keep the aspect ratio here + copybit_device_t* copybit = mLayer.mBlitEngine; + const int down = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT); + const int up = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT); + if (buffers.w > w*down) w = buffers.w / down; + else if (w > buffers.w*up) w = buffers.w*up; + if (buffers.h > h*down) h = buffers.h / down; + else if (h > buffers.h*up) h = buffers.h*up; + if (mTexture.image != EGL_NO_IMAGE_KHR) { // we have an EGLImage, make sure the needed size didn't change if (w!=mTexture.width || h!= mTexture.height) { // delete the EGLImage and texture - EGLDisplay dpy(mLayer.mFlinger->graphicPlane(0).getEGLDisplay()); - glDeleteTextures(1, &mTexture.name); - eglDestroyImageKHR(dpy, mTexture.image); - Texture defaultTexture; - mTexture = defaultTexture; - mTempGraphicBuffer.clear(); + clearTempBufferImage(); } else { // we're good, we have an EGLImageKHR and it's (still) the // right size @@ -528,45 +573,52 @@ status_t LayerBuffer::BufferSource::initTempBuffer() const } // Allocate a temporary buffer and create the corresponding EGLImageKHR - - status_t err; - mTempGraphicBuffer.clear(); - mTempGraphicBuffer = new GraphicBuffer( + // once the EGLImage has been created we don't need the + // graphic buffer reference anymore. + sp<GraphicBuffer> buffer = new GraphicBuffer( w, h, HAL_PIXEL_FORMAT_RGB_565, GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_HW_2D); - err = mTempGraphicBuffer->initCheck(); + status_t err = buffer->initCheck(); if (err == NO_ERROR) { NativeBuffer& dst(mTempBuffer); - dst.img.w = mTempGraphicBuffer->getStride(); + dst.img.w = buffer->getStride(); dst.img.h = h; - dst.img.format = mTempGraphicBuffer->getPixelFormat(); - dst.img.handle = (native_handle_t *)mTempGraphicBuffer->handle; + dst.img.format = buffer->getPixelFormat(); + dst.img.handle = (native_handle_t *)buffer->handle; dst.img.base = 0; dst.crop.l = 0; dst.crop.t = 0; dst.crop.r = w; dst.crop.b = h; - err = mLayer.initializeEglImage( - mTempGraphicBuffer, &mTexture); - // once the EGLImage has been created (whether it fails - // or not) we don't need the graphic buffer reference - // anymore. - mTempGraphicBuffer.clear(); + err = mLayer.initializeEglImage(buffer, &mTexture); } return err; } +void LayerBuffer::BufferSource::clearTempBufferImage() const +{ + // delete the image + EGLDisplay dpy(mLayer.mFlinger->graphicPlane(0).getEGLDisplay()); + eglDestroyImageKHR(dpy, mTexture.image); + + // and the associated texture (recreate a name) + glDeleteTextures(1, &mTexture.name); + Texture defaultTexture; + mTexture = defaultTexture; + mTexture.name = mLayer.createTexture(); +} + // --------------------------------------------------------------------------- LayerBuffer::OverlaySource::OverlaySource(LayerBuffer& layer, sp<OverlayRef>* overlayRef, - uint32_t w, uint32_t h, int32_t format) + uint32_t w, uint32_t h, int32_t format, int32_t orientation) : Source(layer), mVisibilityChanged(false), - mOverlay(0), mOverlayHandle(0), mOverlayDevice(0) + mOverlay(0), mOverlayHandle(0), mOverlayDevice(0), mOrientation(orientation) { overlay_control_device_t* overlay_dev = mLayer.mFlinger->getOverlayEngine(); if (overlay_dev == NULL) { @@ -648,8 +700,12 @@ void LayerBuffer::OverlaySource::onVisibilityResolved( if (mOverlay) { overlay_control_device_t* overlay_dev = mOverlayDevice; overlay_dev->setPosition(overlay_dev, mOverlay, x,y,w,h); + // we need to combine the layer orientation and the + // user-requested orientation. + Transform finalTransform = Transform(mOrientation) * + Transform(mLayer.getOrientation()); overlay_dev->setParameter(overlay_dev, mOverlay, - OVERLAY_TRANSFORM, mLayer.getOrientation()); + OVERLAY_TRANSFORM, finalTransform.getOrientation()); overlay_dev->commit(overlay_dev, mOverlay); } } diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h index 2ca63ac..b176623 100644 --- a/libs/surfaceflinger/LayerBuffer.h +++ b/libs/surfaceflinger/LayerBuffer.h @@ -74,7 +74,8 @@ public: status_t registerBuffers(const ISurface::BufferHeap& buffers); void postBuffer(ssize_t offset); void unregisterBuffers(); - sp<OverlayRef> createOverlay(uint32_t w, uint32_t h, int32_t format); + sp<OverlayRef> createOverlay(uint32_t w, uint32_t h, int32_t format, + int32_t orientation); sp<Source> getSource() const; sp<Source> clearSource(); @@ -98,7 +99,11 @@ private: class Buffer : public LightRefBase<Buffer> { public: - Buffer(const ISurface::BufferHeap& buffers, ssize_t offset); + Buffer(const ISurface::BufferHeap& buffers, + ssize_t offset, size_t bufferSize); + inline bool supportsCopybit() const { + return mSupportsCopybit; + } inline status_t getStatus() const { return mBufferHeap.heap!=0 ? NO_ERROR : NO_INIT; } @@ -113,6 +118,7 @@ private: private: ISurface::BufferHeap mBufferHeap; NativeBuffer mNativeBuffer; + bool mSupportsCopybit; }; class BufferSource : public Source { @@ -131,6 +137,7 @@ private: virtual void destroy() { } private: status_t initTempBuffer() const; + void clearTempBufferImage() const; mutable Mutex mBufferSourceLock; sp<Buffer> mBuffer; status_t mStatus; @@ -138,14 +145,14 @@ private: size_t mBufferSize; mutable LayerBase::Texture mTexture; mutable NativeBuffer mTempBuffer; - mutable sp<GraphicBuffer> mTempGraphicBuffer; + mutable bool mUseEGLImageDirectly; }; class OverlaySource : public Source { public: OverlaySource(LayerBuffer& layer, sp<OverlayRef>* overlayRef, - uint32_t w, uint32_t h, int32_t format); + uint32_t w, uint32_t h, int32_t format, int32_t orientation); virtual ~OverlaySource(); virtual void onDraw(const Region& clip) const; virtual void onTransaction(uint32_t flags); @@ -178,6 +185,7 @@ private: int32_t mFormat; int32_t mWidthStride; int32_t mHeightStride; + int32_t mOrientation; mutable Mutex mOverlaySourceLock; bool mInitialized; }; @@ -195,7 +203,7 @@ private: virtual void unregisterBuffers(); virtual sp<OverlayRef> createOverlay( - uint32_t w, uint32_t h, int32_t format); + uint32_t w, uint32_t h, int32_t format, int32_t orientation); private: sp<LayerBuffer> getOwner() const { return static_cast<LayerBuffer*>(Surface::getOwner().get()); diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp index 965b7dd..0722fda 100644 --- a/libs/surfaceflinger/SurfaceFlinger.cpp +++ b/libs/surfaceflinger/SurfaceFlinger.cpp @@ -39,7 +39,6 @@ #include <ui/GraphicBufferAllocator.h> #include <ui/PixelFormat.h> -#include <ui/DisplayInfo.h> #include <pixelflinger/pixelflinger.h> #include <GLES/gl.h> @@ -350,8 +349,8 @@ status_t SurfaceFlinger::readyToRun() mServerCblk->connected |= 1<<dpy; display_cblk_t* dcblk = mServerCblk->displays + dpy; memset(dcblk, 0, sizeof(display_cblk_t)); - dcblk->w = w; - dcblk->h = h; + dcblk->w = plane.getWidth(); + dcblk->h = plane.getHeight(); dcblk->format = f; dcblk->orientation = ISurfaceComposer::eOrientationDefault; dcblk->xdpi = hw.getDpiX(); @@ -621,23 +620,18 @@ void SurfaceFlinger::handleTransactionLocked( const DisplayHardware& hw(plane.displayHardware()); volatile display_cblk_t* dcblk = mServerCblk->displays + dpy; dcblk->orientation = orientation; - if (orientation & eOrientationSwapMask) { - // 90 or 270 degrees orientation - dcblk->w = hw.getHeight(); - dcblk->h = hw.getWidth(); - } else { - dcblk->w = hw.getWidth(); - dcblk->h = hw.getHeight(); - } + dcblk->w = plane.getWidth(); + dcblk->h = plane.getHeight(); mVisibleRegionsDirty = true; mDirtyRegion.set(hw.bounds()); - mFreezeDisplayTime = 0; } if (mCurrentState.freezeDisplay != mDrawingState.freezeDisplay) { // freezing or unfreezing the display -> trigger animation if needed mFreezeDisplay = mCurrentState.freezeDisplay; + if (mFreezeDisplay) + mFreezeDisplayTime = 0; } if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) { @@ -680,6 +674,8 @@ void SurfaceFlinger::computeVisibleRegions( { const GraphicPlane& plane(graphicPlane(0)); const Transform& planeTransform(plane.transform()); + const DisplayHardware& hw(plane.displayHardware()); + const Region screenRegion(hw.bounds()); Region aboveOpaqueLayers; Region aboveCoveredLayers; @@ -695,31 +691,56 @@ void SurfaceFlinger::computeVisibleRegions( // start with the whole surface at its current location const Layer::State& s(layer->drawingState()); - // handle hidden surfaces by setting the visible region to empty + /* + * opaqueRegion: area of a surface that is fully opaque. + */ Region opaqueRegion; + + /* + * visibleRegion: area of a surface that is visible on screen + * and not fully transparent. This is essentially the layer's + * footprint minus the opaque regions above it. + * Areas covered by a translucent surface are considered visible. + */ Region visibleRegion; + + /* + * coveredRegion: area of a surface that is covered by all + * visible regions above it (which includes the translucent areas). + */ Region coveredRegion; + + + // handle hidden surfaces by setting the visible region to empty if (LIKELY(!(s.flags & ISurfaceComposer::eLayerHidden) && s.alpha)) { const bool translucent = layer->needsBlending(); const Rect bounds(layer->visibleBounds()); visibleRegion.set(bounds); - coveredRegion = visibleRegion; - - // Remove the transparent area from the visible region - if (translucent) { - visibleRegion.subtractSelf(layer->transparentRegionScreen); - } + visibleRegion.andSelf(screenRegion); + if (!visibleRegion.isEmpty()) { + // Remove the transparent area from the visible region + if (translucent) { + visibleRegion.subtractSelf(layer->transparentRegionScreen); + } - // compute the opaque region - if (s.alpha==255 && !translucent && layer->getOrientation()>=0) { - // the opaque region is the visible region - opaqueRegion = visibleRegion; + // compute the opaque region + const int32_t layerOrientation = layer->getOrientation(); + if (s.alpha==255 && !translucent && + ((layerOrientation & Transform::ROT_INVALID) == false)) { + // the opaque region is the layer's footprint + opaqueRegion = visibleRegion; + } } } + // Clip the covered region to the visible region + coveredRegion = aboveCoveredLayers.intersect(visibleRegion); + + // Update aboveCoveredLayers for next (lower) layer + aboveCoveredLayers.orSelf(visibleRegion); + // subtract the opaque region covered by the layers above us visibleRegion.subtractSelf(aboveOpaqueLayers); - coveredRegion.andSelf(aboveCoveredLayers); // compute this layer's dirty region if (layer->contentDirty) { @@ -730,19 +751,30 @@ void SurfaceFlinger::computeVisibleRegions( layer->contentDirty = false; } else { /* compute the exposed region: - * exposed = what's VISIBLE and NOT COVERED now - * but was COVERED before + * the exposed region consists of two components: + * 1) what's VISIBLE now and was COVERED before + * 2) what's EXPOSED now less what was EXPOSED before + * + * note that (1) is conservative, we start with the whole + * visible region but only keep what used to be covered by + * something -- which mean it may have been exposed. + * + * (2) handles areas that were not covered by anything but got + * exposed because of a resize. */ - dirty = (visibleRegion - coveredRegion) & layer->coveredRegionScreen; + const Region newExposed = visibleRegion - coveredRegion; + const Region oldVisibleRegion = layer->visibleRegionScreen; + const Region oldCoveredRegion = layer->coveredRegionScreen; + const Region oldExposed = oldVisibleRegion - oldCoveredRegion; + dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed); } dirty.subtractSelf(aboveOpaqueLayers); // accumulate to the screen dirty region dirtyRegion.orSelf(dirty); - // Update aboveOpaqueLayers/aboveCoveredLayers for next (lower) layer + // Update aboveOpaqueLayers for next (lower) layer aboveOpaqueLayers.orSelf(opaqueRegion); - aboveCoveredLayers.orSelf(visibleRegion); // Store the visible region is screen space layer->setVisibleRegion(visibleRegion); @@ -1193,7 +1225,7 @@ int SurfaceFlinger::setOrientation(DisplayID dpy, } sp<ISurface> SurfaceFlinger::createSurface(ClientID clientId, int pid, - ISurfaceFlingerClient::surface_data_t* params, + const String8& name, ISurfaceFlingerClient::surface_data_t* params, DisplayID d, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) { @@ -1239,6 +1271,7 @@ sp<ISurface> SurfaceFlinger::createSurface(ClientID clientId, int pid, } if (layer != 0) { + layer->setName(name); setTransactionFlags(eTransactionNeeded); surfaceHandle = layer->getSurface(); if (surfaceHandle != 0) { @@ -1503,8 +1536,8 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) layer->needsBlending(), layer->needsDithering(), layer->contentDirty, s.alpha, s.flags, - s.transform[0], s.transform[1], - s.transform[2], s.transform[3]); + s.transform[0][0], s.transform[0][1], + s.transform[1][0], s.transform[1][1]); result.append(buffer); buffer[0] = 0; /*** LayerBaseClient ***/ @@ -1513,8 +1546,10 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) if (lbc != 0) { sp<Client> client(lbc->client.promote()); snprintf(buffer, SIZE, - " " - "id=0x%08x, client=0x%08x, identity=%u\n", + " name=%s\n", lbc->getName().string()); + result.append(buffer); + snprintf(buffer, SIZE, + " id=0x%08x, client=0x%08x, identity=%u\n", lbc->clientIndex(), client.get() ? client->cid : 0, lbc->getIdentity()); @@ -1763,10 +1798,12 @@ sp<IMemoryHeap> BClient::getControlBlock() const { sp<ISurface> BClient::createSurface( ISurfaceFlingerClient::surface_data_t* params, int pid, + const String8& name, DisplayID display, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) { - return mFlinger->createSurface(mId, pid, params, display, w, h, format, flags); + return mFlinger->createSurface(mId, pid, name, params, display, w, h, + format, flags); } status_t BClient::destroySurface(SurfaceID sid) @@ -1795,72 +1832,94 @@ bool GraphicPlane::initialized() const { return mHw ? true : false; } -void GraphicPlane::setDisplayHardware(DisplayHardware *hw) { - mHw = hw; +int GraphicPlane::getWidth() const { + return mWidth; } -void GraphicPlane::setTransform(const Transform& tr) { - mTransform = tr; - mGlobalTransform = mOrientationTransform * mTransform; +int GraphicPlane::getHeight() const { + return mHeight; +} + +void GraphicPlane::setDisplayHardware(DisplayHardware *hw) +{ + mHw = hw; + + // initialize the display orientation transform. + // it's a constant that should come from the display driver. + int displayOrientation = ISurfaceComposer::eOrientationDefault; + char property[PROPERTY_VALUE_MAX]; + if (property_get("ro.sf.hwrotation", property, NULL) > 0) { + //displayOrientation + switch (atoi(property)) { + case 90: + displayOrientation = ISurfaceComposer::eOrientation90; + break; + case 270: + displayOrientation = ISurfaceComposer::eOrientation270; + break; + } + } + + const float w = hw->getWidth(); + const float h = hw->getHeight(); + GraphicPlane::orientationToTransfrom(displayOrientation, w, h, + &mDisplayTransform); + if (displayOrientation & ISurfaceComposer::eOrientationSwapMask) { + mDisplayWidth = h; + mDisplayHeight = w; + } else { + mDisplayWidth = w; + mDisplayHeight = h; + } + + setOrientation(ISurfaceComposer::eOrientationDefault); } status_t GraphicPlane::orientationToTransfrom( int orientation, int w, int h, Transform* tr) -{ - float a, b, c, d, x, y; +{ + uint32_t flags = 0; switch (orientation) { case ISurfaceComposer::eOrientationDefault: - a=1; b=0; c=0; d=1; x=0; y=0; + flags = Transform::ROT_0; break; case ISurfaceComposer::eOrientation90: - a=0; b=-1; c=1; d=0; x=w; y=0; + flags = Transform::ROT_90; break; case ISurfaceComposer::eOrientation180: - a=-1; b=0; c=0; d=-1; x=w; y=h; + flags = Transform::ROT_180; break; case ISurfaceComposer::eOrientation270: - a=0; b=1; c=-1; d=0; x=0; y=h; + flags = Transform::ROT_270; break; default: return BAD_VALUE; } - tr->set(a, b, c, d); - tr->set(x, y); + tr->set(flags, w, h); return NO_ERROR; } status_t GraphicPlane::setOrientation(int orientation) { - const DisplayHardware& hw(displayHardware()); - const float w = hw.getWidth(); - const float h = hw.getHeight(); - - if (orientation == ISurfaceComposer::eOrientationDefault) { - // make sure the default orientation is optimal - mOrientationTransform.reset(); - mOrientation = orientation; - mGlobalTransform = mTransform; - return NO_ERROR; - } - // If the rotation can be handled in hardware, this is where // the magic should happen. - if (UNLIKELY(orientation == 42)) { - float a, b, c, d, x, y; - const float r = (3.14159265f / 180.0f) * 42.0f; - const float si = sinf(r); - const float co = cosf(r); - a=co; b=-si; c=si; d=co; - x = si*(h*0.5f) + (1-co)*(w*0.5f); - y =-si*(w*0.5f) + (1-co)*(h*0.5f); - mOrientationTransform.set(a, b, c, d); - mOrientationTransform.set(x, y); - } else { - GraphicPlane::orientationToTransfrom(orientation, w, h, - &mOrientationTransform); + + const DisplayHardware& hw(displayHardware()); + const float w = mDisplayWidth; + const float h = mDisplayHeight; + mWidth = int(w); + mHeight = int(h); + + Transform orientationTransform; + GraphicPlane::orientationToTransfrom(orientation, w, h, + &orientationTransform); + if (orientation & ISurfaceComposer::eOrientationSwapMask) { + mWidth = int(h); + mHeight = int(w); } + mOrientation = orientation; - mGlobalTransform = mOrientationTransform * mTransform; + mGlobalTransform = mDisplayTransform * orientationTransform; return NO_ERROR; } diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h index c0ab73d..d75dc15 100644 --- a/libs/surfaceflinger/SurfaceFlinger.h +++ b/libs/surfaceflinger/SurfaceFlinger.h @@ -31,11 +31,8 @@ #include <binder/Permission.h> #include <ui/PixelFormat.h> -#include <ui/ISurfaceComposer.h> -#include <ui/ISurfaceFlingerClient.h> - -#include <private/ui/SharedBufferStack.h> -#include <private/ui/LayerState.h> +#include <surfaceflinger/ISurfaceComposer.h> +#include <surfaceflinger/ISurfaceFlingerClient.h> #include "Barrier.h" #include "Layer.h" @@ -116,9 +113,10 @@ public: bool initialized() const; void setDisplayHardware(DisplayHardware *); - void setTransform(const Transform& tr); status_t setOrientation(int orientation); int getOrientation() const { return mOrientation; } + int getWidth() const; + int getHeight() const; const DisplayHardware& displayHardware() const; const Transform& transform() const; @@ -129,10 +127,13 @@ private: GraphicPlane operator = (const GraphicPlane&); DisplayHardware* mHw; - Transform mTransform; - Transform mOrientationTransform; Transform mGlobalTransform; + Transform mDisplayTransform; int mOrientation; + float mDisplayWidth; + float mDisplayHeight; + int mWidth; + int mHeight; }; // --------------------------------------------------------------------------- @@ -188,7 +189,7 @@ private: friend class LayerBlur; friend class LayerDim; - sp<ISurface> createSurface(ClientID client, int pid, + sp<ISurface> createSurface(ClientID client, int pid, const String8& name, ISurfaceFlingerClient::surface_data_t* params, DisplayID display, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags); @@ -400,7 +401,7 @@ public: virtual sp<IMemoryHeap> getControlBlock() const; virtual sp<ISurface> createSurface( - surface_data_t* params, int pid, + surface_data_t* params, int pid, const String8& name, DisplayID display, uint32_t w, uint32_t h,PixelFormat format, uint32_t flags); diff --git a/libs/surfaceflinger/Transform.cpp b/libs/surfaceflinger/Transform.cpp index 1501536..175f989 100644 --- a/libs/surfaceflinger/Transform.cpp +++ b/libs/surfaceflinger/Transform.cpp @@ -14,169 +14,262 @@ * limitations under the License. */ -#include <ui/Region.h> +#include <math.h> -#include <private/pixelflinger/ggl_fixed.h> +#include <cutils/compiler.h> +#include <utils/String8.h> +#include <ui/Region.h> #include "Transform.h" // --------------------------------------------------------------------------- -#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) -#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) +namespace android { // --------------------------------------------------------------------------- -namespace android { +template <typename T> inline T min(T a, T b) { + return a<b ? a : b; +} +template <typename T> inline T min(T a, T b, T c) { + return min(a, min(b, c)); +} +template <typename T> inline T min(T a, T b, T c, T d) { + return min(a, b, min(c, d)); +} + +template <typename T> inline T max(T a, T b) { + return a>b ? a : b; +} +template <typename T> inline T max(T a, T b, T c) { + return max(a, max(b, c)); +} +template <typename T> inline T max(T a, T b, T c, T d) { + return max(a, b, max(c, d)); +} // --------------------------------------------------------------------------- -Transform::Transform() - : mType(0) -{ - mTransform.reset(); +Transform::Transform() { + reset(); } Transform::Transform(const Transform& other) - : mTransform(other.mTransform), mType(other.mType) -{ + : mMatrix(other.mMatrix), mType(other.mType) { +} + +Transform::Transform(uint32_t orientation) { + set(orientation, 0, 0); } Transform::~Transform() { } +static const float EPSILON = 0.0f; + +bool Transform::isZero(float f) { + return fabs(f) <= EPSILON; +} + +bool Transform::absIsOne(float f) { + return isZero(fabs(f) - 1.0f); +} + Transform Transform::operator * (const Transform& rhs) const { - if (LIKELY(mType == 0)) + if (CC_LIKELY(mType == IDENTITY)) return rhs; Transform r(*this); - r.mTransform.preConcat(rhs.mTransform); - r.mType |= rhs.mType; - return r; -} + if (rhs.mType == IDENTITY) + return r; -float Transform::operator [] (int i) const -{ - float r = 0; - switch(i) { - case 0: r = SkScalarToFloat( mTransform[SkMatrix::kMScaleX] ); break; - case 1: r = SkScalarToFloat( mTransform[SkMatrix::kMSkewX] ); break; - case 2: r = SkScalarToFloat( mTransform[SkMatrix::kMSkewY] ); break; - case 3: r = SkScalarToFloat( mTransform[SkMatrix::kMScaleY] ); break; + // TODO: we could use mType to optimize the matrix multiply + const mat33& A(mMatrix); + const mat33& B(rhs.mMatrix); + mat33& D(r.mMatrix); + for (int i=0 ; i<3 ; i++) { + const float v0 = A[0][i]; + const float v1 = A[1][i]; + const float v2 = A[2][i]; + D[0][i] = v0*B[0][0] + v1*B[0][1] + v2*B[0][2]; + D[1][i] = v0*B[1][0] + v1*B[1][1] + v2*B[1][2]; + D[2][i] = v0*B[2][0] + v1*B[2][1] + v2*B[2][2]; } + r.mType |= rhs.mType; + + // TODO: we could recompute this value from r and rhs + r.mType &= 0xFF; + r.mType |= UNKNOWN_TYPE; return r; } -uint8_t Transform::type() const -{ - if (UNLIKELY(mType & 0x80000000)) { - mType = mTransform.getType(); - } - return uint8_t(mType & 0xFF); +float const* Transform::operator [] (int i) const { + return mMatrix[i].v; } bool Transform::transformed() const { - return type() > SkMatrix::kTranslate_Mask; + return type() > TRANSLATE; } int Transform::tx() const { - return SkScalarRound( mTransform[SkMatrix::kMTransX] ); + return floorf(mMatrix[2][0] + 0.5f); } int Transform::ty() const { - return SkScalarRound( mTransform[SkMatrix::kMTransY] ); + return floorf(mMatrix[2][1] + 0.5f); } void Transform::reset() { - mTransform.reset(); - mType = 0; + mType = IDENTITY; + for(int i=0 ; i<3 ; i++) { + vec3& v(mMatrix[i]); + for (int j=0 ; j<3 ; j++) + v[j] = ((i==j) ? 1.0f : 0.0f); + } } -void Transform::set( float xx, float xy, - float yx, float yy) +void Transform::set(float tx, float ty) { - mTransform.set(SkMatrix::kMScaleX, SkFloatToScalar(xx)); - mTransform.set(SkMatrix::kMSkewX, SkFloatToScalar(xy)); - mTransform.set(SkMatrix::kMSkewY, SkFloatToScalar(yx)); - mTransform.set(SkMatrix::kMScaleY, SkFloatToScalar(yy)); - mType |= 0x80000000; + mMatrix[2][0] = tx; + mMatrix[2][1] = ty; + mMatrix[2][2] = 1.0f; + + if (isZero(tx) && isZero(ty)) { + mType &= ~TRANSLATE; + } else { + mType |= TRANSLATE; + } } -void Transform::set(float radian, float x, float y) +void Transform::set(float a, float b, float c, float d) { - float r00 = cosf(radian); float r01 = -sinf(radian); - float r10 = sinf(radian); float r11 = cosf(radian); - mTransform.set(SkMatrix::kMScaleX, SkFloatToScalar(r00)); - mTransform.set(SkMatrix::kMSkewX, SkFloatToScalar(r01)); - mTransform.set(SkMatrix::kMSkewY, SkFloatToScalar(r10)); - mTransform.set(SkMatrix::kMScaleY, SkFloatToScalar(r11)); - mTransform.set(SkMatrix::kMTransX, SkIntToScalar(x - r00*x - r01*y)); - mTransform.set(SkMatrix::kMTransY, SkIntToScalar(y - r10*x - r11*y)); - mType |= 0x80000000 | SkMatrix::kTranslate_Mask; -} - -void Transform::scale(float s, float x, float y) -{ - mTransform.postScale(s, s, x, y); - mType |= 0x80000000; + mat33& M(mMatrix); + M[0][0] = a; M[1][0] = b; + M[0][1] = c; M[1][1] = d; + M[0][2] = 0; M[1][2] = 0; + mType = UNKNOWN_TYPE; } -void Transform::set(int tx, int ty) +status_t Transform::set(uint32_t flags, float w, float h) { - if (tx | ty) { - mTransform.set(SkMatrix::kMTransX, SkIntToScalar(tx)); - mTransform.set(SkMatrix::kMTransY, SkIntToScalar(ty)); - mType |= SkMatrix::kTranslate_Mask; + if (flags & ROT_INVALID) { + // that's not allowed! + reset(); + return BAD_VALUE; + } + + mType = flags << 8; + float sx = (flags & FLIP_H) ? -1 : 1; + float sy = (flags & FLIP_V) ? -1 : 1; + float a=0, b=0, c=0, d=0, x=0, y=0; + int xmask = 0; + + // computation of x,y + // x y + // 0 0 0 + // w 0 ROT90 + // w h FLIPH|FLIPV + // 0 h FLIPH|FLIPV|ROT90 + + if (flags & ROT_90) { + mType |= ROTATE; + b = -sy; + c = sx; + xmask = 1; } else { - mTransform.set(SkMatrix::kMTransX, 0); - mTransform.set(SkMatrix::kMTransY, 0); - mType &= ~SkMatrix::kTranslate_Mask; + a = sx; + d = sy; + } + + if (flags & FLIP_H) { + mType ^= SCALE; + xmask ^= 1; + } + + if (flags & FLIP_V) { + mType ^= SCALE; + y = h; + } + + if ((flags & ROT_180) == ROT_180) { + mType |= ROTATE; + } + + if (xmask) { + x = w; } + + if (!isZero(x) || !isZero(y)) { + mType |= TRANSLATE; + } + + mat33& M(mMatrix); + M[0][0] = a; M[1][0] = b; M[2][0] = x; + M[0][1] = c; M[1][1] = d; M[2][1] = y; + M[0][2] = 0; M[1][2] = 0; M[2][2] = 1; + + return NO_ERROR; } -void Transform::transform(GLfixed* point, int x, int y) const +Transform::vec2 Transform::transform(const vec2& v) const { + vec2 r; + const mat33& M(mMatrix); + r[0] = M[0][0]*v[0] + M[1][0]*v[1] + M[2][0]; + r[1] = M[0][1]*v[0] + M[1][1]*v[1] + M[2][1]; + return r; +} + +Transform::vec3 Transform::transform(const vec3& v) const { + vec3 r; + const mat33& M(mMatrix); + r[0] = M[0][0]*v[0] + M[1][0]*v[1] + M[2][0]*v[2]; + r[1] = M[0][1]*v[0] + M[1][1]*v[1] + M[2][1]*v[2]; + r[2] = M[0][2]*v[0] + M[1][2]*v[1] + M[2][2]*v[2]; + return r; +} + +void Transform::transform(fixed1616* point, int x, int y) const { - SkPoint s; - mTransform.mapXY(SkIntToScalar(x), SkIntToScalar(y), &s); - point[0] = SkScalarToFixed(s.fX); - point[1] = SkScalarToFixed(s.fY); + const float toFixed = 65536.0f; + const mat33& M(mMatrix); + vec2 v(x, y); + v = transform(v); + point[0] = v[0] * toFixed; + point[1] = v[1] * toFixed; } Rect Transform::makeBounds(int w, int h) const { - Rect r; - SkRect d, s; - s.set(0, 0, SkIntToScalar(w), SkIntToScalar(h)); - mTransform.mapRect(&d, s); - r.left = SkScalarRound( d.fLeft ); - r.top = SkScalarRound( d.fTop ); - r.right = SkScalarRound( d.fRight ); - r.bottom = SkScalarRound( d.fBottom ); - return r; + return transform( Rect(w, h) ); } Rect Transform::transform(const Rect& bounds) const { Rect r; - SkRect d, s; - s.set( SkIntToScalar( bounds.left ), - SkIntToScalar( bounds.top ), - SkIntToScalar( bounds.right ), - SkIntToScalar( bounds.bottom )); - mTransform.mapRect(&d, s); - r.left = SkScalarRound( d.fLeft ); - r.top = SkScalarRound( d.fTop ); - r.right = SkScalarRound( d.fRight ); - r.bottom = SkScalarRound( d.fBottom ); + vec2 lt( bounds.left, bounds.top ); + vec2 rt( bounds.right, bounds.top ); + vec2 lb( bounds.left, bounds.bottom ); + vec2 rb( bounds.right, bounds.bottom ); + + lt = transform(lt); + rt = transform(rt); + lb = transform(lb); + rb = transform(rb); + + r.left = floorf(min(lt[0], rt[0], lb[0], rb[0]) + 0.5f); + r.top = floorf(min(lt[1], rt[1], lb[1], rb[1]) + 0.5f); + r.right = floorf(max(lt[0], rt[0], lb[0], rb[0]) + 0.5f); + r.bottom = floorf(max(lt[1], rt[1], lb[1], rb[1]) + 0.5f); + return r; } Region Transform::transform(const Region& reg) const { Region out; - if (UNLIKELY(transformed())) { - if (LIKELY(preserveRects())) { + if (CC_UNLIKELY(transformed())) { + if (CC_LIKELY(preserveRects())) { Region::const_iterator it = reg.begin(); Region::const_iterator const end = reg.end(); while (it != end) { @@ -191,31 +284,107 @@ Region Transform::transform(const Region& reg) const return out; } -int32_t Transform::getOrientation() const +uint32_t Transform::type() const { - uint32_t flags = 0; - if (UNLIKELY(transformed())) { - SkScalar a = mTransform[SkMatrix::kMScaleX]; - SkScalar b = mTransform[SkMatrix::kMSkewX]; - SkScalar c = mTransform[SkMatrix::kMSkewY]; - SkScalar d = mTransform[SkMatrix::kMScaleY]; - if (b==0 && c==0 && a && d) { + if (mType & UNKNOWN_TYPE) { + // recompute what this transform is + + const mat33& M(mMatrix); + const float a = M[0][0]; + const float b = M[1][0]; + const float c = M[0][1]; + const float d = M[1][1]; + const float x = M[2][0]; + const float y = M[2][1]; + + bool scale = false; + uint32_t flags = ROT_0; + if (isZero(b) && isZero(c)) { if (a<0) flags |= FLIP_H; if (d<0) flags |= FLIP_V; - } else if (b && c && a==0 && d==0) { + if (!absIsOne(a) || !absIsOne(d)) { + scale = true; + } + } else if (isZero(a) && isZero(d)) { flags |= ROT_90; if (b>0) flags |= FLIP_H; if (c<0) flags |= FLIP_V; + if (!absIsOne(b) || !absIsOne(c)) { + scale = true; + } + } else { + flags = ROT_INVALID; + } + + mType = flags << 8; + if (flags & ROT_INVALID) { + mType |= UNKNOWN; } else { - flags = 0x80000000; + if ((flags & ROT_90) || ((flags & ROT_180) == ROT_180)) + mType |= ROTATE; + if (flags & FLIP_H) + mType ^= SCALE; + if (flags & FLIP_V) + mType ^= SCALE; + if (scale) + mType |= SCALE; } + + if (!isZero(x) || !isZero(y)) + mType |= TRANSLATE; } - return flags; + return mType; +} + +uint32_t Transform::getType() const { + return type() & 0xFF; +} + +uint32_t Transform::getOrientation() const +{ + return (type() >> 8) & 0xFF; } bool Transform::preserveRects() const { - return mTransform.rectStaysRect(); + return (type() & ROT_INVALID) ? false : true; +} + +void Transform::dump(const char* name) const +{ + type(); // updates the type + + String8 flags, type; + const mat33& m(mMatrix); + uint32_t orient = mType >> 8; + + if (orient&ROT_INVALID) { + flags.append("ROT_INVALID "); + } else { + if (orient&ROT_90) { + flags.append("ROT_90 "); + } else { + flags.append("ROT_0 "); + } + if (orient&FLIP_V) + flags.append("FLIP_V "); + if (orient&FLIP_H) + flags.append("FLIP_H "); + } + + if (!(mType&(SCALE|ROTATE|TRANSLATE))) + type.append("IDENTITY "); + if (mType&SCALE) + type.append("SCALE "); + if (mType&ROTATE) + type.append("ROTATE "); + if (mType&TRANSLATE) + type.append("TRANSLATE "); + + LOGD("%s 0x%08x (%s, %s)", name, mType, flags.string(), type.string()); + LOGD("%.4f %.4f %.4f", m[0][0], m[1][0], m[2][0]); + LOGD("%.4f %.4f %.4f", m[0][1], m[1][1], m[2][1]); + LOGD("%.4f %.4f %.4f", m[0][2], m[1][2], m[2][2]); } // --------------------------------------------------------------------------- diff --git a/libs/surfaceflinger/Transform.h b/libs/surfaceflinger/Transform.h index 78f5c19..2e5b893 100644 --- a/libs/surfaceflinger/Transform.h +++ b/libs/surfaceflinger/Transform.h @@ -23,10 +23,6 @@ #include <ui/Point.h> #include <ui/Rect.h> -#include <GLES/gl.h> - -#include <core/SkMatrix.h> - namespace android { class Region; @@ -38,8 +34,12 @@ class Transform public: Transform(); Transform(const Transform& other); + explicit Transform(uint32_t orientation); ~Transform(); + typedef int32_t fixed1616; + + // FIXME: must match OVERLAY_TRANSFORM_*, pull from hardware.h enum orientation_flags { ROT_0 = 0x00000000, FLIP_H = 0x00000001, @@ -47,48 +47,79 @@ public: ROT_90 = 0x00000004, ROT_180 = FLIP_H|FLIP_V, ROT_270 = ROT_180|ROT_90, - ROT_INVALID = 0x80000000 + ROT_INVALID = 0x80 }; enum type_mask { IDENTITY = 0, TRANSLATE = 0x1, - SCALE = 0x2, - AFFINE = 0x4, - PERSPECTIVE = 0x8 + ROTATE = 0x2, + SCALE = 0x4, + UNKNOWN = 0x8 }; - bool transformed() const; - int32_t getOrientation() const; - bool preserveRects() const; - + // query the transform + bool transformed() const; + bool preserveRects() const; + uint32_t getType() const; + uint32_t getOrientation() const; + + float const* operator [] (int i) const; // returns column i int tx() const; int ty() const; - - void reset(); - void set(float xx, float xy, float yx, float yy); - void set(int tx, int ty); - void set(float radian, float x, float y); - void scale(float s, float x, float y); - + + // modify the transform + void reset(); + void set(float tx, float ty); + void set(float a, float b, float c, float d); + status_t set(uint32_t flags, float w, float h); + + // transform data Rect makeBounds(int w, int h) const; - void transform(GLfixed* point, int x, int y) const; + void transform(fixed1616* point, int x, int y) const; Region transform(const Region& reg) const; - Rect transform(const Rect& bounds) const; - Transform operator * (const Transform& rhs) const; - float operator [] (int i) const; - inline uint32_t getType() const { return type(); } - - inline Transform(bool) : mType(0xFF) { }; - -private: - uint8_t type() const; + // for debugging + void dump(const char* name) const; private: - SkMatrix mTransform; - mutable uint32_t mType; + struct vec3 { + float v[3]; + inline vec3() { } + inline vec3(float a, float b, float c) { + v[0] = a; v[1] = b; v[2] = c; + } + inline float operator [] (int i) const { return v[i]; } + inline float& operator [] (int i) { return v[i]; } + }; + struct vec2 { + float v[2]; + inline vec2() { } + inline vec2(float a, float b) { + v[0] = a; v[1] = b; + } + inline float operator [] (int i) const { return v[i]; } + inline float& operator [] (int i) { return v[i]; } + }; + struct mat33 { + vec3 v[3]; + inline const vec3& operator [] (int i) const { return v[i]; } + inline vec3& operator [] (int i) { return v[i]; } + }; + + enum { UNKNOWN_TYPE = 0x80000000 }; + + // assumes the last row is < 0 , 0 , 1 > + vec2 transform(const vec2& v) const; + vec3 transform(const vec3& v) const; + Rect transform(const Rect& bounds) const; + uint32_t type() const; + static bool absIsOne(float f); + static bool isZero(float f); + + mat33 mMatrix; + mutable uint32_t mType; }; // --------------------------------------------------------------------------- diff --git a/libs/surfaceflinger/tests/overlays/Android.mk b/libs/surfaceflinger/tests/overlays/Android.mk index dc47e45..592b601 100644 --- a/libs/surfaceflinger/tests/overlays/Android.mk +++ b/libs/surfaceflinger/tests/overlays/Android.mk @@ -7,7 +7,8 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils \ - libui + libui \ + libsurfaceflinger_client LOCAL_MODULE:= test-overlays diff --git a/libs/surfaceflinger/tests/overlays/overlays.cpp b/libs/surfaceflinger/tests/overlays/overlays.cpp index 0b9322e..c248a615 100644 --- a/libs/surfaceflinger/tests/overlays/overlays.cpp +++ b/libs/surfaceflinger/tests/overlays/overlays.cpp @@ -3,10 +3,11 @@ #include <binder/IServiceManager.h> #include <utils/Log.h> -#include <ui/Surface.h> -#include <ui/ISurface.h> #include <ui/Overlay.h> -#include <ui/SurfaceComposerClient.h> + +#include <surfaceflinger/Surface.h> +#include <surfaceflinger/ISurface.h> +#include <surfaceflinger/SurfaceComposerClient.h> using namespace android; diff --git a/libs/surfaceflinger/tests/resize/Android.mk b/libs/surfaceflinger/tests/resize/Android.mk index ef1532f..24c2d01 100644 --- a/libs/surfaceflinger/tests/resize/Android.mk +++ b/libs/surfaceflinger/tests/resize/Android.mk @@ -7,7 +7,8 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils \ - libui + libui \ + libsurfaceflinger_client LOCAL_MODULE:= test-resize diff --git a/libs/surfaceflinger/tests/resize/resize.cpp b/libs/surfaceflinger/tests/resize/resize.cpp index 21c6ab6..127cca3 100644 --- a/libs/surfaceflinger/tests/resize/resize.cpp +++ b/libs/surfaceflinger/tests/resize/resize.cpp @@ -1,14 +1,16 @@ #include <cutils/memory.h> -#include <utils/IPCThreadState.h> -#include <utils/ProcessState.h> -#include <utils/IServiceManager.h> #include <utils/Log.h> -#include <ui/Surface.h> -#include <ui/ISurface.h> +#include <binder/IPCThreadState.h> +#include <binder/ProcessState.h> +#include <binder/IServiceManager.h> + +#include <surfaceflinger/Surface.h> +#include <surfaceflinger/ISurface.h> +#include <surfaceflinger/SurfaceComposerClient.h> + #include <ui/Overlay.h> -#include <ui/SurfaceComposerClient.h> using namespace android; diff --git a/libs/surfaceflinger_client/Android.mk b/libs/surfaceflinger_client/Android.mk new file mode 100644 index 0000000..fe85b34 --- /dev/null +++ b/libs/surfaceflinger_client/Android.mk @@ -0,0 +1,26 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + ISurfaceComposer.cpp \ + ISurface.cpp \ + ISurfaceFlingerClient.cpp \ + LayerState.cpp \ + SharedBufferStack.cpp \ + Surface.cpp \ + SurfaceComposerClient.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libutils \ + libbinder \ + libhardware \ + libui + +LOCAL_MODULE:= libsurfaceflinger_client + +ifeq ($(TARGET_SIMULATOR),true) + LOCAL_LDLIBS += -lpthread +endif + +include $(BUILD_SHARED_LIBRARY) diff --git a/libs/ui/ISurface.cpp b/libs/surfaceflinger_client/ISurface.cpp index 4fb38ed..bb86199 100644 --- a/libs/ui/ISurface.cpp +++ b/libs/surfaceflinger_client/ISurface.cpp @@ -23,12 +23,12 @@ #include <binder/Parcel.h> #include <binder/IMemory.h> -#include <ui/ISurface.h> #include <ui/Overlay.h> -#include <ui/Surface.h> - #include <ui/GraphicBuffer.h> +#include <surfaceflinger/Surface.h> +#include <surfaceflinger/ISurface.h> + namespace android { // ---------------------------------------------------------------------- @@ -78,7 +78,8 @@ public: data.writeInt32(bufferIdx); data.writeInt32(usage); remote()->transact(REQUEST_BUFFER, data, &reply); - sp<GraphicBuffer> buffer = new GraphicBuffer(reply); + sp<GraphicBuffer> buffer = new GraphicBuffer(); + reply.read(*buffer); return buffer; } @@ -115,13 +116,14 @@ public: } virtual sp<OverlayRef> createOverlay( - uint32_t w, uint32_t h, int32_t format) + uint32_t w, uint32_t h, int32_t format, int32_t orientation) { Parcel data, reply; data.writeInterfaceToken(ISurface::getInterfaceDescriptor()); data.writeInt32(w); data.writeInt32(h); data.writeInt32(format); + data.writeInt32(orientation); remote()->transact(CREATE_OVERLAY, data, &reply); return OverlayRef::readFromParcel(reply); } @@ -140,7 +142,9 @@ status_t BnSurface::onTransact( int bufferIdx = data.readInt32(); int usage = data.readInt32(); sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, usage)); - return GraphicBuffer::writeToParcel(reply, buffer.get()); + if (buffer == NULL) + return BAD_VALUE; + return reply->write(*buffer); } case REGISTER_BUFFERS: { CHECK_INTERFACE(ISurface, data, reply); @@ -173,7 +177,8 @@ status_t BnSurface::onTransact( int w = data.readInt32(); int h = data.readInt32(); int f = data.readInt32(); - sp<OverlayRef> o = createOverlay(w, h, f); + int orientation = data.readInt32(); + sp<OverlayRef> o = createOverlay(w, h, f, orientation); return OverlayRef::writeToParcel(reply, o); } break; default: diff --git a/libs/ui/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp index fd2a590..b6f4e24 100644 --- a/libs/ui/ISurfaceComposer.cpp +++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp @@ -25,9 +25,10 @@ #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> -#include <ui/ISurfaceComposer.h> #include <ui/DisplayInfo.h> +#include <surfaceflinger/ISurfaceComposer.h> + // --------------------------------------------------------------------------- #define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) diff --git a/libs/ui/ISurfaceFlingerClient.cpp b/libs/surfaceflinger_client/ISurfaceFlingerClient.cpp index 4a6a1d7..def96d7 100644 --- a/libs/ui/ISurfaceFlingerClient.cpp +++ b/libs/surfaceflinger_client/ISurfaceFlingerClient.cpp @@ -26,12 +26,12 @@ #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> -#include <ui/ISurface.h> -#include <ui/ISurfaceFlingerClient.h> #include <ui/Point.h> #include <ui/Rect.h> -#include <private/ui/LayerState.h> +#include <surfaceflinger/ISurface.h> +#include <surfaceflinger/ISurfaceFlingerClient.h> +#include <private/surfaceflinger/LayerState.h> // --------------------------------------------------------------------------- @@ -74,6 +74,7 @@ public: virtual sp<ISurface> createSurface( surface_data_t* params, int pid, + const String8& name, DisplayID display, uint32_t w, uint32_t h, @@ -83,6 +84,7 @@ public: Parcel data, reply; data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor()); data.writeInt32(pid); + data.writeString8(name); data.writeInt32(display); data.writeInt32(w); data.writeInt32(h); @@ -154,12 +156,14 @@ status_t BnSurfaceFlingerClient::onTransact( CHECK_INTERFACE(ISurfaceFlingerClient, data, reply); surface_data_t params; int32_t pid = data.readInt32(); + String8 name = data.readString8(); DisplayID display = data.readInt32(); uint32_t w = data.readInt32(); uint32_t h = data.readInt32(); PixelFormat format = data.readInt32(); uint32_t flags = data.readInt32(); - sp<ISurface> s = createSurface(¶ms, pid, display, w, h, format, flags); + sp<ISurface> s = createSurface(¶ms, pid, name, display, w, h, + format, flags); params.writeToParcel(reply); reply->writeStrongBinder(s->asBinder()); return NO_ERROR; diff --git a/libs/ui/LayerState.cpp b/libs/surfaceflinger_client/LayerState.cpp index a53ffb7..01c4c7e 100644 --- a/libs/ui/LayerState.cpp +++ b/libs/surfaceflinger_client/LayerState.cpp @@ -16,37 +16,45 @@ #include <utils/Errors.h> #include <binder/Parcel.h> -#include <private/ui/LayerState.h> +#include <private/surfaceflinger/LayerState.h> namespace android { status_t layer_state_t::write(Parcel& output) const { - size_t size = sizeof(layer_state_t); + status_t err; + + size_t len = transparentRegion.write(NULL, 0); + err = output.writeInt32(len); + if (err < NO_ERROR) return err; - //output.writeStrongBinder(surface->asBinder()); - //size -= sizeof(surface); + void* buf = output.writeInplace(len); + if (buf == NULL) return NO_MEMORY; - transparentRegion.write(output); + err = transparentRegion.write(buf, len); + if (err < NO_ERROR) return err; + + // NOTE: regions are at the end of the structure + size_t size = sizeof(layer_state_t); size -= sizeof(transparentRegion); - - output.write(this, size); - - return NO_ERROR; + err = output.write(this, size); + return err; } status_t layer_state_t::read(const Parcel& input) { - size_t size = sizeof(layer_state_t); + status_t err; + size_t len = input.readInt32(); + void const* buf = input.readInplace(len); + if (buf == NULL) return NO_MEMORY; - //surface = interface_cast<ISurface>(input.readStrongBinder()); - //size -= sizeof(surface); + err = transparentRegion.read(buf); + if (err < NO_ERROR) return err; - transparentRegion.read(input); + // NOTE: regions are at the end of the structure + size_t size = sizeof(layer_state_t); size -= sizeof(transparentRegion); - input.read(this, size); - return NO_ERROR; } diff --git a/libs/ui/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp index 46b6766..a17e8ac 100644 --- a/libs/ui/SharedBufferStack.cpp +++ b/libs/surfaceflinger_client/SharedBufferStack.cpp @@ -23,7 +23,7 @@ #include <utils/Log.h> #include <utils/threads.h> -#include <private/ui/SharedBufferStack.h> +#include <private/surfaceflinger/SharedBufferStack.h> #include <ui/Rect.h> #include <ui/Region.h> @@ -34,7 +34,7 @@ namespace android { // ---------------------------------------------------------------------------- SharedClient::SharedClient() - : lock(Mutex::SHARED) + : lock(Mutex::SHARED), cv(Condition::SHARED) { } @@ -132,10 +132,11 @@ String8 SharedBufferBase::dump(char const* prefix) const char buffer[SIZE]; String8 result; SharedBufferStack& stack( *mSharedStack ); + int tail = (mNumBuffers + stack.head - stack.available + 1) % mNumBuffers; snprintf(buffer, SIZE, - "%s[ head=%2d, available=%2d, queued=%2d ] " + "%s[ head=%2d, available=%2d, queued=%2d, tail=%2d ] " "reallocMask=%08x, inUse=%2d, identity=%d, status=%d\n", - prefix, stack.head, stack.available, stack.queued, + prefix, stack.head, stack.available, stack.queued, tail, stack.reallocMask, stack.inUse, stack.identity, stack.status); result.append(buffer); return result; @@ -269,6 +270,8 @@ int32_t SharedBufferClient::computeTail() const newTail = head - avail + 1; if (newTail < 0) { newTail += mNumBuffers; + } else if (newTail >= mNumBuffers) { + newTail -= mNumBuffers; } return newTail; } diff --git a/libs/ui/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp index 24ae27f..5dd75c3 100644 --- a/libs/ui/Surface.cpp +++ b/libs/surfaceflinger_client/Surface.cpp @@ -26,22 +26,25 @@ #include <utils/Errors.h> #include <utils/threads.h> #include <utils/CallStack.h> +#include <utils/Log.h> + +#include <pixelflinger/pixelflinger.h> + #include <binder/IPCThreadState.h> #include <binder/IMemory.h> -#include <utils/Log.h> #include <ui/DisplayInfo.h> #include <ui/GraphicBuffer.h> #include <ui/GraphicBufferMapper.h> -#include <ui/ISurface.h> -#include <ui/Surface.h> -#include <ui/SurfaceComposerClient.h> #include <ui/Rect.h> -#include <pixelflinger/pixelflinger.h> +#include <surfaceflinger/Surface.h> +#include <surfaceflinger/ISurface.h> +#include <surfaceflinger/ISurfaceComposer.h> +#include <surfaceflinger/SurfaceComposerClient.h> -#include <private/ui/SharedBufferStack.h> -#include <private/ui/LayerState.h> +#include <private/surfaceflinger/SharedBufferStack.h> +#include <private/surfaceflinger/LayerState.h> namespace android { @@ -350,6 +353,7 @@ void Surface::init() const_cast<uint32_t&>(android_native_window_t::flags) = 0; // be default we request a hardware surface mUsage = GRALLOC_USAGE_HW_RENDER; + mConnected = 0; mNeedFullUpdate = false; } @@ -576,28 +580,93 @@ int Surface::perform(int operation, va_list args) { int res = NO_ERROR; switch (operation) { - case NATIVE_WINDOW_SET_USAGE: - setUsage( va_arg(args, int) ); - break; - default: - res = NAME_NOT_FOUND; - break; + case NATIVE_WINDOW_SET_USAGE: + dispatch_setUsage( args ); + break; + case NATIVE_WINDOW_CONNECT: + res = dispatch_connect( args ); + break; + case NATIVE_WINDOW_DISCONNECT: + res = dispatch_disconnect( args ); + break; + default: + res = NAME_NOT_FOUND; + break; } return res; } +void Surface::dispatch_setUsage(va_list args) { + int usage = va_arg(args, int); + setUsage( usage ); +} +int Surface::dispatch_connect(va_list args) { + int api = va_arg(args, int); + return connect( api ); +} +int Surface::dispatch_disconnect(va_list args) { + int api = va_arg(args, int); + return disconnect( api ); +} + + void Surface::setUsage(uint32_t reqUsage) { Mutex::Autolock _l(mSurfaceLock); mUsage = reqUsage; } +int Surface::connect(int api) +{ + Mutex::Autolock _l(mSurfaceLock); + int err = NO_ERROR; + switch (api) { + case NATIVE_WINDOW_API_EGL: + if (mConnected) { + err = -EINVAL; + } else { + mConnected = api; + } + break; + default: + err = -EINVAL; + break; + } + return err; +} + +int Surface::disconnect(int api) +{ + Mutex::Autolock _l(mSurfaceLock); + int err = NO_ERROR; + switch (api) { + case NATIVE_WINDOW_API_EGL: + if (mConnected == api) { + mConnected = 0; + } else { + err = -EINVAL; + } + break; + default: + err = -EINVAL; + break; + } + return err; +} + uint32_t Surface::getUsage() const { Mutex::Autolock _l(mSurfaceLock); return mUsage; } +int Surface::getConnectedApi() const +{ + Mutex::Autolock _l(mSurfaceLock); + return mConnected; +} + + // ---------------------------------------------------------------------------- status_t Surface::lock(SurfaceInfo* info, bool blocking) { @@ -606,14 +675,31 @@ status_t Surface::lock(SurfaceInfo* info, bool blocking) { status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking) { + if (getConnectedApi()) { + LOGE("Surface::lock(%p) failed. Already connected to another API", + (android_native_window_t*)this); + CallStack stack; + stack.update(); + stack.dump(""); + return INVALID_OPERATION; + } + if (mApiLock.tryLock() != NO_ERROR) { - LOGE("calling Surface::lock() from different threads!"); + LOGE("calling Surface::lock from different threads!"); CallStack stack; stack.update(); - stack.dump("Surface::lock called from different threads"); + stack.dump(""); return WOULD_BLOCK; } + + /* Here we're holding mApiLock */ + if (mLockedBuffer != 0) { + LOGE("Surface::lock failed, already locked"); + mApiLock.unlock(); + return INVALID_OPERATION; + } + // we're intending to do software rendering from this point setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); @@ -682,8 +768,8 @@ status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking) status_t Surface::unlockAndPost() { if (mLockedBuffer == 0) { - LOGE("unlockAndPost failed, no locked buffer"); - return BAD_VALUE; + LOGE("Surface::unlockAndPost failed, no locked buffer"); + return INVALID_OPERATION; } status_t err = mLockedBuffer->unlock(); diff --git a/libs/ui/SurfaceComposerClient.cpp b/libs/surfaceflinger_client/SurfaceComposerClient.cpp index eda84ef..3117495 100644 --- a/libs/ui/SurfaceComposerClient.cpp +++ b/libs/surfaceflinger_client/SurfaceComposerClient.cpp @@ -29,19 +29,21 @@ #include <utils/Errors.h> #include <utils/threads.h> #include <utils/KeyedVector.h> +#include <utils/Log.h> + #include <binder/IServiceManager.h> #include <binder/IMemory.h> -#include <utils/Log.h> #include <ui/DisplayInfo.h> -#include <ui/ISurfaceComposer.h> -#include <ui/ISurfaceFlingerClient.h> -#include <ui/ISurface.h> -#include <ui/SurfaceComposerClient.h> #include <ui/Rect.h> -#include <private/ui/LayerState.h> -#include <private/ui/SharedBufferStack.h> +#include <surfaceflinger/ISurfaceComposer.h> +#include <surfaceflinger/ISurfaceFlingerClient.h> +#include <surfaceflinger/ISurface.h> +#include <surfaceflinger/SurfaceComposerClient.h> + +#include <private/surfaceflinger/LayerState.h> +#include <private/surfaceflinger/SharedBufferStack.h> #define VERBOSE(...) ((void)0) //#define VERBOSE LOGD @@ -317,10 +319,30 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface( PixelFormat format, uint32_t flags) { + String8 name; + const size_t SIZE = 128; + char buffer[SIZE]; + snprintf(buffer, SIZE, "<pid_%d>", getpid()); + name.append(buffer); + + return SurfaceComposerClient::createSurface(pid, name, display, + w, h, format, flags); + +} + +sp<SurfaceControl> SurfaceComposerClient::createSurface( + int pid, + const String8& name, + DisplayID display, + uint32_t w, + uint32_t h, + PixelFormat format, + uint32_t flags) +{ sp<SurfaceControl> result; if (mStatus == NO_ERROR) { ISurfaceFlingerClient::surface_data_t data; - sp<ISurface> surface = mClient->createSurface(&data, pid, + sp<ISurface> surface = mClient->createSurface(&data, pid, name, display, w, h, format, flags); if (surface != 0) { if (uint32_t(data.token) < NUM_LAYERS_MAX) { diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk index 84aec61..f7acd97 100644 --- a/libs/ui/Android.mk +++ b/libs/ui/Android.mk @@ -2,8 +2,6 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ - Camera.cpp \ - CameraParameters.cpp \ EGLUtils.cpp \ EventHub.cpp \ EventRecurrence.cpp \ @@ -13,21 +11,11 @@ LOCAL_SRC_FILES:= \ GraphicBufferMapper.cpp \ KeyLayoutMap.cpp \ KeyCharacterMap.cpp \ - ICamera.cpp \ - ICameraClient.cpp \ - ICameraService.cpp \ IOverlay.cpp \ - ISurfaceComposer.cpp \ - ISurface.cpp \ - ISurfaceFlingerClient.cpp \ - LayerState.cpp \ Overlay.cpp \ PixelFormat.cpp \ Rect.cpp \ - Region.cpp \ - SharedBufferStack.cpp \ - Surface.cpp \ - SurfaceComposerClient.cpp + Region.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp deleted file mode 100644 index 09a36f1..0000000 --- a/libs/ui/Camera.cpp +++ /dev/null @@ -1,356 +0,0 @@ -/* -** -** 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 -** -** 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_NDEBUG 0 -#define LOG_TAG "Camera" -#include <utils/Log.h> -#include <binder/IServiceManager.h> -#include <utils/threads.h> -#include <binder/IMemory.h> -#include <ui/Surface.h> -#include <ui/Camera.h> -#include <ui/ICameraService.h> - -namespace android { - -// client singleton for camera service binder interface -Mutex Camera::mLock; -sp<ICameraService> Camera::mCameraService; -sp<Camera::DeathNotifier> Camera::mDeathNotifier; - -// establish binder interface to camera service -const sp<ICameraService>& Camera::getCameraService() -{ - Mutex::Autolock _l(mLock); - if (mCameraService.get() == 0) { - sp<IServiceManager> sm = defaultServiceManager(); - sp<IBinder> binder; - do { - binder = sm->getService(String16("media.camera")); - if (binder != 0) - break; - LOGW("CameraService not published, waiting..."); - usleep(500000); // 0.5 s - } while(true); - if (mDeathNotifier == NULL) { - mDeathNotifier = new DeathNotifier(); - } - binder->linkToDeath(mDeathNotifier); - mCameraService = interface_cast<ICameraService>(binder); - } - LOGE_IF(mCameraService==0, "no CameraService!?"); - return mCameraService; -} - -// --------------------------------------------------------------------------- - -Camera::Camera() -{ - init(); -} - -// construct a camera client from an existing camera remote -sp<Camera> Camera::create(const sp<ICamera>& camera) -{ - LOGV("create"); - if (camera == 0) { - LOGE("camera remote is a NULL pointer"); - return 0; - } - - sp<Camera> c = new Camera(); - if (camera->connect(c) == NO_ERROR) { - c->mStatus = NO_ERROR; - c->mCamera = camera; - camera->asBinder()->linkToDeath(c); - } - return c; -} - -void Camera::init() -{ - mStatus = UNKNOWN_ERROR; -} - -Camera::~Camera() -{ - disconnect(); -} - -sp<Camera> Camera::connect() -{ - LOGV("connect"); - sp<Camera> c = new Camera(); - const sp<ICameraService>& cs = getCameraService(); - if (cs != 0) { - c->mCamera = cs->connect(c); - } - if (c->mCamera != 0) { - c->mCamera->asBinder()->linkToDeath(c); - c->mStatus = NO_ERROR; - } else { - c.clear(); - } - return c; -} - -void Camera::disconnect() -{ - LOGV("disconnect"); - if (mCamera != 0) { - mCamera->disconnect(); - mCamera = 0; - } -} - -status_t Camera::reconnect() -{ - LOGV("reconnect"); - sp <ICamera> c = mCamera; - if (c == 0) return NO_INIT; - return c->connect(this); -} - -sp<ICamera> Camera::remote() -{ - return mCamera; -} - -status_t Camera::lock() -{ - sp <ICamera> c = mCamera; - if (c == 0) return NO_INIT; - return c->lock(); -} - -status_t Camera::unlock() -{ - sp <ICamera> c = mCamera; - if (c == 0) return NO_INIT; - return c->unlock(); -} - -// pass the buffered ISurface to the camera service -status_t Camera::setPreviewDisplay(const sp<Surface>& surface) -{ - LOGV("setPreviewDisplay"); - sp <ICamera> c = mCamera; - if (c == 0) return NO_INIT; - if (surface != 0) { - return c->setPreviewDisplay(surface->getISurface()); - } else { - LOGD("app passed NULL surface"); - return c->setPreviewDisplay(0); - } -} - -status_t Camera::setPreviewDisplay(const sp<ISurface>& surface) -{ - LOGV("setPreviewDisplay"); - if (surface == 0) { - LOGD("app passed NULL surface"); - } - sp <ICamera> c = mCamera; - if (c == 0) return NO_INIT; - return c->setPreviewDisplay(surface); -} - - -// start preview mode -status_t Camera::startPreview() -{ - LOGV("startPreview"); - sp <ICamera> c = mCamera; - if (c == 0) return NO_INIT; - return c->startPreview(); -} - -// start recording mode, must call setPreviewDisplay first -status_t Camera::startRecording() -{ - LOGV("startRecording"); - sp <ICamera> c = mCamera; - if (c == 0) return NO_INIT; - return c->startRecording(); -} - -// stop preview mode -void Camera::stopPreview() -{ - LOGV("stopPreview"); - sp <ICamera> c = mCamera; - if (c == 0) return; - c->stopPreview(); -} - -// stop recording mode -void Camera::stopRecording() -{ - LOGV("stopRecording"); - sp <ICamera> c = mCamera; - if (c == 0) return; - c->stopRecording(); -} - -// release a recording frame -void Camera::releaseRecordingFrame(const sp<IMemory>& mem) -{ - LOGV("releaseRecordingFrame"); - sp <ICamera> c = mCamera; - if (c == 0) return; - c->releaseRecordingFrame(mem); -} - -// get preview state -bool Camera::previewEnabled() -{ - LOGV("previewEnabled"); - sp <ICamera> c = mCamera; - if (c == 0) return false; - return c->previewEnabled(); -} - -// get recording state -bool Camera::recordingEnabled() -{ - LOGV("recordingEnabled"); - sp <ICamera> c = mCamera; - if (c == 0) return false; - return c->recordingEnabled(); -} - -status_t Camera::autoFocus() -{ - LOGV("autoFocus"); - sp <ICamera> c = mCamera; - if (c == 0) return NO_INIT; - return c->autoFocus(); -} - -status_t Camera::cancelAutoFocus() -{ - LOGV("cancelAutoFocus"); - sp <ICamera> c = mCamera; - if (c == 0) return NO_INIT; - return c->cancelAutoFocus(); -} - -// take a picture -status_t Camera::takePicture() -{ - LOGV("takePicture"); - sp <ICamera> c = mCamera; - if (c == 0) return NO_INIT; - return c->takePicture(); -} - -// set preview/capture parameters - key/value pairs -status_t Camera::setParameters(const String8& params) -{ - LOGV("setParameters"); - sp <ICamera> c = mCamera; - if (c == 0) return NO_INIT; - return c->setParameters(params); -} - -// get preview/capture parameters - key/value pairs -String8 Camera::getParameters() const -{ - LOGV("getParameters"); - String8 params; - sp <ICamera> c = mCamera; - if (c != 0) params = mCamera->getParameters(); - return params; -} - -// send command to camera driver -status_t Camera::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) -{ - LOGD("sendCommand"); - sp <ICamera> c = mCamera; - if (c == 0) return NO_INIT; - return c->sendCommand(cmd, arg1, arg2); -} - -void Camera::setListener(const sp<CameraListener>& listener) -{ - Mutex::Autolock _l(mLock); - mListener = listener; -} - -void Camera::setPreviewCallbackFlags(int flag) -{ - LOGV("setPreviewCallbackFlags"); - sp <ICamera> c = mCamera; - if (c == 0) return; - mCamera->setPreviewCallbackFlag(flag); -} - -// callback from camera service -void Camera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) -{ - sp<CameraListener> listener; - { - Mutex::Autolock _l(mLock); - listener = mListener; - } - if (listener != NULL) { - listener->notify(msgType, ext1, ext2); - } -} - -// callback from camera service when frame or image is ready -void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr) -{ - sp<CameraListener> listener; - { - Mutex::Autolock _l(mLock); - listener = mListener; - } - if (listener != NULL) { - listener->postData(msgType, dataPtr); - } -} - -// callback from camera service when timestamped frame is ready -void Camera::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) -{ - sp<CameraListener> listener; - { - Mutex::Autolock _l(mLock); - listener = mListener; - } - if (listener != NULL) { - listener->postDataTimestamp(timestamp, msgType, dataPtr); - } -} - -void Camera::binderDied(const wp<IBinder>& who) { - LOGW("ICamera died"); - notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_SERVER_DIED, 0); -} - -void Camera::DeathNotifier::binderDied(const wp<IBinder>& who) { - LOGV("binderDied"); - Mutex::Autolock _l(Camera::mLock); - Camera::mCameraService.clear(); - LOGW("Camera server died!"); -} - -}; // namespace android - diff --git a/libs/ui/CameraParameters.cpp b/libs/ui/CameraParameters.cpp deleted file mode 100644 index 8f1749d..0000000 --- a/libs/ui/CameraParameters.cpp +++ /dev/null @@ -1,370 +0,0 @@ -/* -** -** Copyright 2008, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#define LOG_TAG "CameraParams" -#include <utils/Log.h> - -#include <string.h> -#include <stdlib.h> -#include <ui/CameraParameters.h> - -namespace android { -// Parameter keys to communicate between camera application and driver. -const char CameraParameters::KEY_PREVIEW_SIZE[] = "preview-size"; -const char CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES[] = "preview-size-values"; -const char CameraParameters::KEY_PREVIEW_FORMAT[] = "preview-format"; -const char CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS[] = "preview-format-values"; -const char CameraParameters::KEY_PREVIEW_FRAME_RATE[] = "preview-frame-rate"; -const char CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES[] = "preview-frame-rate-values"; -const char CameraParameters::KEY_PICTURE_SIZE[] = "picture-size"; -const char CameraParameters::KEY_SUPPORTED_PICTURE_SIZES[] = "picture-size-values"; -const char CameraParameters::KEY_PICTURE_FORMAT[] = "picture-format"; -const char CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS[] = "picture-format-values"; -const char CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH[] = "jpeg-thumbnail-width"; -const char CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT[] = "jpeg-thumbnail-height"; -const char CameraParameters::KEY_SUPPORTED_THUMBNAIL_SIZES[] = "jpeg-thumbnail-size-values"; -const char CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY[] = "jpeg-thumbnail-quality"; -const char CameraParameters::KEY_JPEG_QUALITY[] = "jpeg-quality"; -const char CameraParameters::KEY_ROTATION[] = "rotation"; -const char CameraParameters::KEY_GPS_LATITUDE[] = "gps-latitude"; -const char CameraParameters::KEY_GPS_LONGITUDE[] = "gps-longitude"; -const char CameraParameters::KEY_GPS_ALTITUDE[] = "gps-altitude"; -const char CameraParameters::KEY_GPS_TIMESTAMP[] = "gps-timestamp"; -const char CameraParameters::KEY_WHITE_BALANCE[] = "whitebalance"; -const char CameraParameters::KEY_SUPPORTED_WHITE_BALANCE[] = "whitebalance-values"; -const char CameraParameters::KEY_EFFECT[] = "effect"; -const char CameraParameters::KEY_SUPPORTED_EFFECTS[] = "effect-values"; -const char CameraParameters::KEY_ANTIBANDING[] = "antibanding"; -const char CameraParameters::KEY_SUPPORTED_ANTIBANDING[] = "antibanding-values"; -const char CameraParameters::KEY_SCENE_MODE[] = "scene-mode"; -const char CameraParameters::KEY_SUPPORTED_SCENE_MODES[] = "scene-mode-values"; -const char CameraParameters::KEY_FLASH_MODE[] = "flash-mode"; -const char CameraParameters::KEY_SUPPORTED_FLASH_MODES[] = "flash-mode-values"; -const char CameraParameters::KEY_FOCUS_MODE[] = "focus-mode"; -const char CameraParameters::KEY_SUPPORTED_FOCUS_MODES[] = "focus-mode-values"; - -// Values for white balance settings. -const char CameraParameters::WHITE_BALANCE_AUTO[] = "auto"; -const char CameraParameters::WHITE_BALANCE_INCANDESCENT[] = "incandescent"; -const char CameraParameters::WHITE_BALANCE_FLUORESCENT[] = "fluorescent"; -const char CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT[] = "warm-fluorescent"; -const char CameraParameters::WHITE_BALANCE_DAYLIGHT[] = "daylight"; -const char CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT[] = "cloudy-daylight"; -const char CameraParameters::WHITE_BALANCE_TWILIGHT[] = "twilight"; -const char CameraParameters::WHITE_BALANCE_SHADE[] = "shade"; - -// Values for effect settings. -const char CameraParameters::EFFECT_NONE[] = "none"; -const char CameraParameters::EFFECT_MONO[] = "mono"; -const char CameraParameters::EFFECT_NEGATIVE[] = "negative"; -const char CameraParameters::EFFECT_SOLARIZE[] = "solarize"; -const char CameraParameters::EFFECT_SEPIA[] = "sepia"; -const char CameraParameters::EFFECT_POSTERIZE[] = "posterize"; -const char CameraParameters::EFFECT_WHITEBOARD[] = "whiteboard"; -const char CameraParameters::EFFECT_BLACKBOARD[] = "blackboard"; -const char CameraParameters::EFFECT_AQUA[] = "aqua"; - -// Values for antibanding settings. -const char CameraParameters::ANTIBANDING_AUTO[] = "auto"; -const char CameraParameters::ANTIBANDING_50HZ[] = "50hz"; -const char CameraParameters::ANTIBANDING_60HZ[] = "60hz"; -const char CameraParameters::ANTIBANDING_OFF[] = "off"; - -// Values for flash mode settings. -const char CameraParameters::FLASH_MODE_OFF[] = "off"; -const char CameraParameters::FLASH_MODE_AUTO[] = "auto"; -const char CameraParameters::FLASH_MODE_ON[] = "on"; -const char CameraParameters::FLASH_MODE_RED_EYE[] = "red-eye"; -const char CameraParameters::FLASH_MODE_TORCH[] = "torch"; - -// Values for scene mode settings. -const char CameraParameters::SCENE_MODE_AUTO[] = "auto"; -const char CameraParameters::SCENE_MODE_ACTION[] = "action"; -const char CameraParameters::SCENE_MODE_PORTRAIT[] = "portrait"; -const char CameraParameters::SCENE_MODE_LANDSCAPE[] = "landscape"; -const char CameraParameters::SCENE_MODE_NIGHT[] = "night"; -const char CameraParameters::SCENE_MODE_NIGHT_PORTRAIT[] = "night-portrait"; -const char CameraParameters::SCENE_MODE_THEATRE[] = "theatre"; -const char CameraParameters::SCENE_MODE_BEACH[] = "beach"; -const char CameraParameters::SCENE_MODE_SNOW[] = "snow"; -const char CameraParameters::SCENE_MODE_SUNSET[] = "sunset"; -const char CameraParameters::SCENE_MODE_STEADYPHOTO[] = "steadyphoto"; -const char CameraParameters::SCENE_MODE_FIREWORKS[] = "fireworks"; -const char CameraParameters::SCENE_MODE_SPORTS[] = "sports"; -const char CameraParameters::SCENE_MODE_PARTY[] = "party"; -const char CameraParameters::SCENE_MODE_CANDLELIGHT[] = "candlelight"; - -// Formats for setPreviewFormat and setPictureFormat. -const char CameraParameters::PIXEL_FORMAT_YUV422SP[] = "yuv422sp"; -const char CameraParameters::PIXEL_FORMAT_YUV420SP[] = "yuv420sp"; -const char CameraParameters::PIXEL_FORMAT_YUV422I[] = "yuv422i-yuyv"; -const char CameraParameters::PIXEL_FORMAT_RGB565[] = "rgb565"; -const char CameraParameters::PIXEL_FORMAT_JPEG[] = "jpeg"; - -// Values for focus mode settings. -const char CameraParameters::FOCUS_MODE_AUTO[] = "auto"; -const char CameraParameters::FOCUS_MODE_INFINITY[] = "infinity"; -const char CameraParameters::FOCUS_MODE_MACRO[] = "macro"; -const char CameraParameters::FOCUS_MODE_FIXED[] = "fixed"; - -static const char* portrait = "portrait"; -static const char* landscape = "landscape"; - -CameraParameters::CameraParameters() - : mMap() -{ -} - -CameraParameters::~CameraParameters() -{ -} - -String8 CameraParameters::flatten() const -{ - String8 flattened(""); - size_t size = mMap.size(); - - for (size_t i = 0; i < size; i++) { - String8 k, v; - k = mMap.keyAt(i); - v = mMap.valueAt(i); - - flattened += k; - flattened += "="; - flattened += v; - if (i != size-1) - flattened += ";"; - } - - return flattened; -} - -void CameraParameters::unflatten(const String8 ¶ms) -{ - const char *a = params.string(); - const char *b; - - mMap.clear(); - - for (;;) { - // Find the bounds of the key name. - b = strchr(a, '='); - if (b == 0) - break; - - // Create the key string. - String8 k(a, (size_t)(b-a)); - - // Find the value. - a = b+1; - b = strchr(a, ';'); - if (b == 0) { - // If there's no semicolon, this is the last item. - String8 v(a); - mMap.add(k, v); - break; - } - - String8 v(a, (size_t)(b-a)); - mMap.add(k, v); - a = b+1; - } -} - - -void CameraParameters::set(const char *key, const char *value) -{ - // XXX i think i can do this with strspn() - if (strchr(key, '=') || strchr(key, ';')) { - //XXX LOGE("Key \"%s\"contains invalid character (= or ;)", key); - return; - } - - if (strchr(value, '=') || strchr(key, ';')) { - //XXX LOGE("Value \"%s\"contains invalid character (= or ;)", value); - return; - } - - mMap.replaceValueFor(String8(key), String8(value)); -} - -void CameraParameters::set(const char *key, int value) -{ - char str[16]; - sprintf(str, "%d", value); - set(key, str); -} - -const char *CameraParameters::get(const char *key) const -{ - String8 v = mMap.valueFor(String8(key)); - if (v.length() == 0) - return 0; - return v.string(); -} - -int CameraParameters::getInt(const char *key) const -{ - const char *v = get(key); - if (v == 0) - return -1; - return strtol(v, 0, 0); -} - -static int parse_size(const char *str, int &width, int &height) -{ - // Find the width. - char *end; - int w = (int)strtol(str, &end, 10); - // If an 'x' does not immediately follow, give up. - if (*end != 'x') - return -1; - - // Find the height, immediately after the 'x'. - int h = (int)strtol(end+1, 0, 10); - - width = w; - height = h; - - return 0; -} - -void CameraParameters::setPreviewSize(int width, int height) -{ - char str[32]; - sprintf(str, "%dx%d", width, height); - set(KEY_PREVIEW_SIZE, str); -} - -void CameraParameters::getPreviewSize(int *width, int *height) const -{ - *width = -1; - *height = -1; - - // Get the current string, if it doesn't exist, leave the -1x-1 - const char *p = get(KEY_PREVIEW_SIZE); - if (p == 0) - return; - - int w, h; - if (parse_size(p, w, h) == 0) { - *width = w; - *height = h; - } -} - -void CameraParameters::setPreviewFrameRate(int fps) -{ - set(KEY_PREVIEW_FRAME_RATE, fps); -} - -int CameraParameters::getPreviewFrameRate() const -{ - return getInt(KEY_PREVIEW_FRAME_RATE); -} - -void CameraParameters::setPreviewFormat(const char *format) -{ - set(KEY_PREVIEW_FORMAT, format); -} - -int CameraParameters::getOrientation() const -{ - const char* orientation = get("orientation"); - if (orientation && !strcmp(orientation, portrait)) - return CAMERA_ORIENTATION_PORTRAIT; - return CAMERA_ORIENTATION_LANDSCAPE; -} - -void CameraParameters::setOrientation(int orientation) -{ - if (orientation == CAMERA_ORIENTATION_PORTRAIT) { - set("orientation", portrait); - } else { - set("orientation", landscape); - } -} - -const char *CameraParameters::getPreviewFormat() const -{ - return get(KEY_PREVIEW_FORMAT); -} - -void CameraParameters::setPictureSize(int width, int height) -{ - char str[32]; - sprintf(str, "%dx%d", width, height); - set(KEY_PICTURE_SIZE, str); -} - -void CameraParameters::getPictureSize(int *width, int *height) const -{ - *width = -1; - *height = -1; - - // Get the current string, if it doesn't exist, leave the -1x-1 - const char *p = get(KEY_PICTURE_SIZE); - if (p == 0) - return; - - int w, h; - if (parse_size(p, w, h) == 0) { - *width = w; - *height = h; - } -} - -void CameraParameters::setPictureFormat(const char *format) -{ - set(KEY_PICTURE_FORMAT, format); -} - -const char *CameraParameters::getPictureFormat() const -{ - return get(KEY_PICTURE_FORMAT); -} - -void CameraParameters::dump() const -{ - LOGD("dump: mMap.size = %d", mMap.size()); - for (size_t i = 0; i < mMap.size(); i++) { - String8 k, v; - k = mMap.keyAt(i); - v = mMap.valueAt(i); - LOGD("%s: %s\n", k.string(), v.string()); - } -} - -status_t CameraParameters::dump(int fd, const Vector<String16>& args) const -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - snprintf(buffer, 255, "CameraParameters::dump: mMap.size = %d\n", mMap.size()); - result.append(buffer); - for (size_t i = 0; i < mMap.size(); i++) { - String8 k, v; - k = mMap.keyAt(i); - v = mMap.valueAt(i); - snprintf(buffer, 255, "\t%s: %s\n", k.string(), v.string()); - result.append(buffer); - } - write(fd, result.string(), result.size()); - return NO_ERROR; -} - -}; // namespace android diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp index 4aac455..d45eaf0 100644 --- a/libs/ui/EventHub.cpp +++ b/libs/ui/EventHub.cpp @@ -176,7 +176,7 @@ int EventHub::getSwitchState(int32_t deviceId, int sw) const if (device == NULL) return -1; if (sw >= 0 && sw <= SW_MAX) { - uint8_t sw_bitmask[(SW_MAX+1)/8]; + uint8_t sw_bitmask[(SW_MAX+7)/8]; memset(sw_bitmask, 0, sizeof(sw_bitmask)); if (ioctl(mFDs[id_to_index(device->id)].fd, EVIOCGSW(sizeof(sw_bitmask)), sw_bitmask) >= 0) { @@ -200,7 +200,7 @@ int EventHub::getScancodeState(int32_t deviceId, int code) const if (device == NULL) return -1; if (code >= 0 && code <= KEY_MAX) { - uint8_t key_bitmask[(KEY_MAX+1)/8]; + uint8_t key_bitmask[(KEY_MAX+7)/8]; memset(key_bitmask, 0, sizeof(key_bitmask)); if (ioctl(mFDs[id_to_index(device->id)].fd, EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) { @@ -225,7 +225,7 @@ int EventHub::getKeycodeState(int32_t deviceId, int code) const Vector<int32_t> scanCodes; device->layoutMap->findScancodes(code, &scanCodes); - uint8_t key_bitmask[(KEY_MAX+1)/8]; + uint8_t key_bitmask[(KEY_MAX+7)/8]; memset(key_bitmask, 0, sizeof(key_bitmask)); if (ioctl(mFDs[id_to_index(device->id)].fd, EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) { @@ -489,7 +489,6 @@ int EventHub::open_device(const char *deviceName) { int version; int fd; - int attempt; struct pollfd *new_mFDs; device_t **new_devices; char **new_device_names; @@ -502,16 +501,11 @@ int EventHub::open_device(const char *deviceName) AutoMutex _l(mLock); - for (attempt = 0; attempt < 10; attempt++) { - fd = open(deviceName, O_RDWR); - if (fd >= 0) break; - usleep(100); - } + fd = open(deviceName, O_RDWR); if(fd < 0) { LOGE("could not open %s, %s\n", deviceName, strerror(errno)); return -1; } - LOGV("Opened device: %s (%d failures)", deviceName, attempt); if(ioctl(fd, EVIOCGVERSION, &version)) { LOGE("could not get driver version for %s, %s\n", deviceName, strerror(errno)); @@ -610,13 +604,16 @@ int EventHub::open_device(const char *deviceName) // figure out the kinds of events the device reports - // See if this is a keyboard, and classify it. - uint8_t key_bitmask[(KEY_MAX+1)/8]; + // See if this is a keyboard, and classify it. Note that we only + // consider up through the function keys; we don't want to include + // ones after that (play cd etc) so we don't mistakenly consider a + // controller to be a keyboard. + uint8_t key_bitmask[(KEY_MAX+7)/8]; memset(key_bitmask, 0, sizeof(key_bitmask)); LOGV("Getting keys..."); if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) { //LOGI("MAP\n"); - //for (int i=0; i<((KEY_MAX+1)/8); i++) { + //for (int i=0; i<((KEY_MAX+7)/8); i++) { // LOGI("%d: 0x%02x\n", i, key_bitmask[i]); //} for (int i=0; i<((BTN_MISC+7)/8); i++) { @@ -639,7 +636,7 @@ int EventHub::open_device(const char *deviceName) // See if this is a trackball. if (test_bit(BTN_MOUSE, key_bitmask)) { - uint8_t rel_bitmask[(REL_MAX+1)/8]; + uint8_t rel_bitmask[(REL_MAX+7)/8]; memset(rel_bitmask, 0, sizeof(rel_bitmask)); LOGV("Getting relative controllers..."); if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0) @@ -650,7 +647,7 @@ int EventHub::open_device(const char *deviceName) } } - uint8_t abs_bitmask[(ABS_MAX+1)/8]; + uint8_t abs_bitmask[(ABS_MAX+7)/8]; memset(abs_bitmask, 0, sizeof(abs_bitmask)); LOGV("Getting absolute controllers..."); ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask); @@ -669,7 +666,7 @@ int EventHub::open_device(const char *deviceName) #ifdef EV_SW // figure out the switches this device reports - uint8_t sw_bitmask[(SW_MAX+1)/8]; + uint8_t sw_bitmask[(SW_MAX+7)/8]; memset(sw_bitmask, 0, sizeof(sw_bitmask)); if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask) >= 0) { for (int i=0; i<EV_SW; i++) { @@ -708,22 +705,20 @@ int EventHub::open_device(const char *deviceName) device->layoutMap->load(keylayoutFilename); // tell the world about the devname (the descriptive name) - int32_t publicID; - if (!mHaveFirstKeyboard && !defaultKeymap) { - publicID = 0; + if (!mHaveFirstKeyboard && !defaultKeymap && strstr(name, "-keypad")) { // the built-in keyboard has a well-known device ID of 0, // this device better not go away. mHaveFirstKeyboard = true; mFirstKeyboardId = device->id; + property_set("hw.keyboards.0.devname", name); } else { - publicID = device->id; // ensure mFirstKeyboardId is set to -something-. if (mFirstKeyboardId == 0) { mFirstKeyboardId = device->id; } } char propName[100]; - sprintf(propName, "hw.keyboards.%u.devname", publicID); + sprintf(propName, "hw.keyboards.%u.devname", device->id); property_set(propName, name); // 'Q' key support = cheap test of whether this is an alpha-capable kbd @@ -740,8 +735,8 @@ int EventHub::open_device(const char *deviceName) device->classes |= CLASS_DPAD; } - LOGI("New keyboard: publicID=%d device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n", - publicID, device->id, name, propName, keylayoutFilename); + LOGI("New keyboard: device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n", + device->id, name, propName, keylayoutFilename); } LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n", @@ -814,18 +809,15 @@ int EventHub::close_device(const char *deviceName) device->next = mClosingDevices; mClosingDevices = device; - uint32_t publicID; if (device->id == mFirstKeyboardId) { LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this", device->path.string(), mFirstKeyboardId); mFirstKeyboardId = 0; - publicID = 0; - } else { - publicID = device->id; + property_set("hw.keyboards.0.devname", NULL); } // clear the property char propName[100]; - sprintf(propName, "hw.keyboards.%u.devname", publicID); + sprintf(propName, "hw.keyboards.%u.devname", device->id); property_set(propName, NULL); return 0; } diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp index c5e22e5..52380a0 100644 --- a/libs/ui/FramebufferNativeWindow.cpp +++ b/libs/ui/FramebufferNativeWindow.cpp @@ -27,7 +27,6 @@ #include <utils/threads.h> #include <utils/RefBase.h> -#include <ui/SurfaceComposerClient.h> #include <ui/Rect.h> #include <ui/FramebufferNativeWindow.h> @@ -251,6 +250,8 @@ int FramebufferNativeWindow::perform(android_native_window_t* window, { switch (operation) { case NATIVE_WINDOW_SET_USAGE: + case NATIVE_WINDOW_CONNECT: + case NATIVE_WINDOW_DISCONNECT: break; default: return NAME_NOT_FOUND; diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index 6a5c8a9..ba1fd9c 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -14,12 +14,12 @@ * limitations under the License. */ +#define LOG_TAG "GraphicBuffer" + #include <stdlib.h> #include <stdint.h> #include <sys/types.h> -#include <binder/Parcel.h> - #include <utils/Errors.h> #include <utils/Log.h> @@ -77,34 +77,21 @@ GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h, handle = inHandle; } -GraphicBuffer::GraphicBuffer(const Parcel& data) - : BASE(), mOwner(ownHandle), mBufferMapper(GraphicBufferMapper::get()), - mInitCheck(NO_ERROR), mVStride(0), mIndex(-1) +GraphicBuffer::~GraphicBuffer() { - // we own the handle in this case - width = data.readInt32(); - if (width < 0) { - width = height = stride = format = usage = 0; - handle = 0; - } else { - height = data.readInt32(); - stride = data.readInt32(); - format = data.readInt32(); - usage = data.readInt32(); - handle = data.readNativeHandle(); + if (handle) { + free_handle(); } } -GraphicBuffer::~GraphicBuffer() +void GraphicBuffer::free_handle() { - if (handle) { - if (mOwner == ownHandle) { - native_handle_close(handle); - native_handle_delete(const_cast<native_handle*>(handle)); - } else if (mOwner == ownData) { - GraphicBufferAllocator& allocator(GraphicBufferAllocator::get()); - allocator.free(handle); - } + if (mOwner == ownHandle) { + native_handle_close(handle); + native_handle_delete(const_cast<native_handle*>(handle)); + } else if (mOwner == ownData) { + GraphicBufferAllocator& allocator(GraphicBufferAllocator::get()); + allocator.free(handle); } } @@ -192,29 +179,83 @@ status_t GraphicBuffer::lock(GGLSurface* sur, uint32_t usage) return res; } +size_t GraphicBuffer::getFlattenedSize() const { + return (8 + (handle ? handle->numInts : 0))*sizeof(int); +} + +size_t GraphicBuffer::getFdCount() const { + return handle ? handle->numFds : 0; +} -status_t GraphicBuffer::writeToParcel(Parcel* reply, - android_native_buffer_t const* buffer) +status_t GraphicBuffer::flatten(void* buffer, size_t size, + int fds[], size_t count) const { - if (buffer == NULL) - return BAD_VALUE; + size_t sizeNeeded = GraphicBuffer::getFlattenedSize(); + if (size < sizeNeeded) return NO_MEMORY; + + size_t fdCountNeeded = GraphicBuffer::getFdCount(); + if (count < fdCountNeeded) return NO_MEMORY; + + int* buf = static_cast<int*>(buffer); + buf[0] = 'GBFR'; + buf[1] = width; + buf[2] = height; + buf[3] = stride; + buf[4] = format; + buf[5] = usage; + buf[6] = 0; + buf[7] = 0; - if (buffer->width < 0 || buffer->height < 0) - return BAD_VALUE; + if (handle) { + buf[6] = handle->numFds; + buf[7] = handle->numInts; + native_handle_t const* const h = handle; + memcpy(fds, h->data, h->numFds*sizeof(int)); + memcpy(&buf[8], h->data + h->numFds, h->numInts*sizeof(int)); + } + + return NO_ERROR; +} + +status_t GraphicBuffer::unflatten(void const* buffer, size_t size, + int fds[], size_t count) +{ + if (size < 8*sizeof(int)) return NO_MEMORY; + + int const* buf = static_cast<int const*>(buffer); + if (buf[0] != 'GBFR') return BAD_TYPE; + + const size_t numFds = buf[6]; + const size_t numInts = buf[7]; - status_t err = NO_ERROR; - if (buffer->handle == NULL) { - // this buffer doesn't have a handle - reply->writeInt32(NO_MEMORY); + const size_t sizeNeeded = (8 + numInts) * sizeof(int); + if (size < sizeNeeded) return NO_MEMORY; + + size_t fdCountNeeded = 0; + if (count < fdCountNeeded) return NO_MEMORY; + + if (handle) { + // free previous handle if any + free_handle(); + } + + if (numFds || numInts) { + width = buf[1]; + height = buf[2]; + stride = buf[3]; + format = buf[4]; + usage = buf[5]; + native_handle* h = native_handle_create(numFds, numInts); + memcpy(h->data, fds, numFds*sizeof(int)); + memcpy(h->data + numFds, &buf[8], numInts*sizeof(int)); + handle = h; } else { - reply->writeInt32(buffer->width); - reply->writeInt32(buffer->height); - reply->writeInt32(buffer->stride); - reply->writeInt32(buffer->format); - reply->writeInt32(buffer->usage); - err = reply->writeNativeHandle(buffer->handle); + width = height = stride = format = usage = 0; + handle = NULL; } - return err; + + mOwner = ownHandle; + return NO_ERROR; } diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp index 57d5fc3..6ae7e74 100644 --- a/libs/ui/GraphicBufferAllocator.cpp +++ b/libs/ui/GraphicBufferAllocator.cpp @@ -78,8 +78,6 @@ static inline uint32_t clamp(uint32_t c) { status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format, int usage, buffer_handle_t* handle, int32_t* stride) { - Mutex::Autolock _l(mLock); - // make sure to not allocate a 0 x 0 buffer w = clamp(w); h = clamp(h); @@ -118,8 +116,6 @@ status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat forma status_t GraphicBufferAllocator::free(buffer_handle_t handle) { - Mutex::Autolock _l(mLock); - status_t err; if (sw_gralloc_handle_t::validate(handle) < 0) { err = mAllocDev->free(mAllocDev, handle); diff --git a/libs/ui/ICamera.cpp b/libs/ui/ICamera.cpp deleted file mode 100644 index e1b3ec7..0000000 --- a/libs/ui/ICamera.cpp +++ /dev/null @@ -1,379 +0,0 @@ -/* -** -** Copyright 2008, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "ICamera" -#include <utils/Log.h> -#include <stdint.h> -#include <sys/types.h> -#include <binder/Parcel.h> -#include <ui/ICamera.h> - -namespace android { - -enum { - DISCONNECT = IBinder::FIRST_CALL_TRANSACTION, - SET_PREVIEW_DISPLAY, - SET_PREVIEW_CALLBACK_FLAG, - START_PREVIEW, - STOP_PREVIEW, - AUTO_FOCUS, - CANCEL_AUTO_FOCUS, - TAKE_PICTURE, - SET_PARAMETERS, - GET_PARAMETERS, - SEND_COMMAND, - CONNECT, - LOCK, - UNLOCK, - PREVIEW_ENABLED, - START_RECORDING, - STOP_RECORDING, - RECORDING_ENABLED, - RELEASE_RECORDING_FRAME, -}; - -class BpCamera: public BpInterface<ICamera> -{ -public: - BpCamera(const sp<IBinder>& impl) - : BpInterface<ICamera>(impl) - { - } - - // disconnect from camera service - void disconnect() - { - LOGV("disconnect"); - Parcel data, reply; - data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); - remote()->transact(DISCONNECT, data, &reply); - } - - // 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(); - } - - // set the preview callback flag to affect how the received frames from - // preview are handled. See Camera.h for details. - void setPreviewCallbackFlag(int flag) - { - LOGV("setPreviewCallbackFlag(%d)", flag); - Parcel data, reply; - data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); - data.writeInt32(flag); - remote()->transact(SET_PREVIEW_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); - return reply.readInt32(); - } - - // start recording mode, must call setPreviewDisplay first - status_t startRecording() - { - LOGV("startRecording"); - Parcel data, reply; - data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); - remote()->transact(START_RECORDING, data, &reply); - return reply.readInt32(); - } - - // stop preview mode - void stopPreview() - { - LOGV("stopPreview"); - Parcel data, reply; - data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); - remote()->transact(STOP_PREVIEW, data, &reply); - } - - // stop recording mode - void stopRecording() - { - LOGV("stopRecording"); - Parcel data, reply; - data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); - remote()->transact(STOP_RECORDING, data, &reply); - } - - void releaseRecordingFrame(const sp<IMemory>& mem) - { - LOGV("releaseRecordingFrame"); - Parcel data, reply; - data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); - data.writeStrongBinder(mem->asBinder()); - remote()->transact(RELEASE_RECORDING_FRAME, data, &reply); - } - - // check preview state - bool previewEnabled() - { - LOGV("previewEnabled"); - Parcel data, reply; - data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); - remote()->transact(PREVIEW_ENABLED, data, &reply); - return reply.readInt32(); - } - - // check recording state - bool recordingEnabled() - { - LOGV("recordingEnabled"); - Parcel data, reply; - data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); - remote()->transact(RECORDING_ENABLED, data, &reply); - return reply.readInt32(); - } - - // auto focus - status_t autoFocus() - { - LOGV("autoFocus"); - Parcel data, reply; - data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); - remote()->transact(AUTO_FOCUS, data, &reply); - status_t ret = reply.readInt32(); - return ret; - } - - // cancel focus - status_t cancelAutoFocus() - { - LOGV("cancelAutoFocus"); - Parcel data, reply; - data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); - remote()->transact(CANCEL_AUTO_FOCUS, data, &reply); - status_t ret = reply.readInt32(); - return ret; - } - - // 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); - status_t ret = reply.readInt32(); - return ret; - } - - // 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); - remote()->transact(SET_PARAMETERS, data, &reply); - return reply.readInt32(); - } - - // 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 sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) - { - LOGD("sendCommand"); - Parcel data, reply; - data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); - data.writeInt32(cmd); - data.writeInt32(arg1); - data.writeInt32(arg2); - remote()->transact(SEND_COMMAND, data, &reply); - return reply.readInt32(); - } - 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(); - } - virtual status_t lock() - { - Parcel data, reply; - data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); - remote()->transact(LOCK, data, &reply); - return reply.readInt32(); - } - virtual status_t unlock() - { - Parcel data, reply; - data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); - remote()->transact(UNLOCK, data, &reply); - return reply.readInt32(); - } -}; - -IMPLEMENT_META_INTERFACE(Camera, "android.hardware.ICamera"); - -// ---------------------------------------------------------------------- - -status_t BnCamera::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - 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_PREVIEW_CALLBACK_FLAG: { - LOGV("SET_PREVIEW_CALLBACK_TYPE"); - CHECK_INTERFACE(ICamera, data, reply); - int callback_flag = data.readInt32(); - setPreviewCallbackFlag(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 START_RECORDING: { - LOGV("START_RECORDING"); - CHECK_INTERFACE(ICamera, data, reply); - reply->writeInt32(startRecording()); - return NO_ERROR; - } break; - case STOP_PREVIEW: { - LOGV("STOP_PREVIEW"); - CHECK_INTERFACE(ICamera, data, reply); - stopPreview(); - return NO_ERROR; - } break; - case STOP_RECORDING: { - LOGV("STOP_RECORDING"); - CHECK_INTERFACE(ICamera, data, reply); - stopRecording(); - return NO_ERROR; - } break; - case RELEASE_RECORDING_FRAME: { - LOGV("RELEASE_RECORDING_FRAME"); - CHECK_INTERFACE(ICamera, data, reply); - sp<IMemory> mem = interface_cast<IMemory>(data.readStrongBinder()); - releaseRecordingFrame(mem); - return NO_ERROR; - } break; - case PREVIEW_ENABLED: { - LOGV("PREVIEW_ENABLED"); - CHECK_INTERFACE(ICamera, data, reply); - reply->writeInt32(previewEnabled()); - return NO_ERROR; - } break; - case RECORDING_ENABLED: { - LOGV("RECORDING_ENABLED"); - CHECK_INTERFACE(ICamera, data, reply); - reply->writeInt32(recordingEnabled()); - return NO_ERROR; - } break; - case AUTO_FOCUS: { - LOGV("AUTO_FOCUS"); - CHECK_INTERFACE(ICamera, data, reply); - reply->writeInt32(autoFocus()); - return NO_ERROR; - } break; - case CANCEL_AUTO_FOCUS: { - LOGV("CANCEL_AUTO_FOCUS"); - CHECK_INTERFACE(ICamera, data, reply); - reply->writeInt32(cancelAutoFocus()); - 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)); - return NO_ERROR; - } break; - case GET_PARAMETERS: { - LOGV("GET_PARAMETERS"); - CHECK_INTERFACE(ICamera, data, reply); - reply->writeString8(getParameters()); - return NO_ERROR; - } break; - case SEND_COMMAND: { - LOGD("SEND_COMMAND"); - CHECK_INTERFACE(ICamera, data, reply); - int command = data.readInt32(); - int arg1 = data.readInt32(); - int arg2 = data.readInt32(); - reply->writeInt32(sendCommand(command, arg1, arg2)); - 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; - case LOCK: { - CHECK_INTERFACE(ICamera, data, reply); - reply->writeInt32(lock()); - return NO_ERROR; - } break; - case UNLOCK: { - CHECK_INTERFACE(ICamera, data, reply); - reply->writeInt32(unlock()); - return NO_ERROR; - } break; - default: - return BBinder::onTransact(code, data, reply, flags); - } -} - -// ---------------------------------------------------------------------------- - -}; // namespace android - diff --git a/libs/ui/ICameraClient.cpp b/libs/ui/ICameraClient.cpp deleted file mode 100644 index 42b4da4..0000000 --- a/libs/ui/ICameraClient.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* -** -** Copyright 2008, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "ICameraClient" -#include <utils/Log.h> -#include <stdint.h> -#include <sys/types.h> -#include <ui/ICameraClient.h> - -namespace android { - -enum { - NOTIFY_CALLBACK = IBinder::FIRST_CALL_TRANSACTION, - DATA_CALLBACK, - DATA_CALLBACK_TIMESTAMP, -}; - -class BpCameraClient: public BpInterface<ICameraClient> -{ -public: - BpCameraClient(const sp<IBinder>& impl) - : BpInterface<ICameraClient>(impl) - { - } - - // generic callback from camera service to app - void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) - { - LOGV("notifyCallback"); - Parcel data, reply; - data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); - data.writeInt32(msgType); - data.writeInt32(ext1); - data.writeInt32(ext2); - remote()->transact(NOTIFY_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); - } - - // generic data callback from camera service to app with image data - void dataCallback(int32_t msgType, const sp<IMemory>& imageData) - { - LOGV("dataCallback"); - Parcel data, reply; - data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); - data.writeInt32(msgType); - data.writeStrongBinder(imageData->asBinder()); - remote()->transact(DATA_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); - } - - // generic data callback from camera service to app with image data - void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& imageData) - { - LOGV("dataCallback"); - Parcel data, reply; - data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); - data.writeInt64(timestamp); - data.writeInt32(msgType); - data.writeStrongBinder(imageData->asBinder()); - remote()->transact(DATA_CALLBACK_TIMESTAMP, data, &reply, IBinder::FLAG_ONEWAY); - } -}; - -IMPLEMENT_META_INTERFACE(CameraClient, "android.hardware.ICameraClient"); - -// ---------------------------------------------------------------------- - -status_t BnCameraClient::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - switch(code) { - case NOTIFY_CALLBACK: { - LOGV("NOTIFY_CALLBACK"); - CHECK_INTERFACE(ICameraClient, data, reply); - int32_t msgType = data.readInt32(); - int32_t ext1 = data.readInt32(); - int32_t ext2 = data.readInt32(); - notifyCallback(msgType, ext1, ext2); - return NO_ERROR; - } break; - case DATA_CALLBACK: { - LOGV("DATA_CALLBACK"); - CHECK_INTERFACE(ICameraClient, data, reply); - int32_t msgType = data.readInt32(); - sp<IMemory> imageData = interface_cast<IMemory>(data.readStrongBinder()); - dataCallback(msgType, imageData); - return NO_ERROR; - } break; - case DATA_CALLBACK_TIMESTAMP: { - LOGV("DATA_CALLBACK_TIMESTAMP"); - CHECK_INTERFACE(ICameraClient, data, reply); - nsecs_t timestamp = data.readInt64(); - int32_t msgType = data.readInt32(); - sp<IMemory> imageData = interface_cast<IMemory>(data.readStrongBinder()); - dataCallbackTimestamp(timestamp, msgType, imageData); - return NO_ERROR; - } break; - default: - return BBinder::onTransact(code, data, reply, flags); - } -} - -// ---------------------------------------------------------------------------- - -}; // namespace android - diff --git a/libs/ui/ICameraService.cpp b/libs/ui/ICameraService.cpp deleted file mode 100644 index 84986c6..0000000 --- a/libs/ui/ICameraService.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* -** -** Copyright 2008, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#include <stdint.h> -#include <sys/types.h> - -#include <binder/Parcel.h> -#include <binder/IPCThreadState.h> -#include <binder/IServiceManager.h> - -#include <ui/ICameraService.h> - -namespace android { - -class BpCameraService: public BpInterface<ICameraService> -{ -public: - BpCameraService(const sp<IBinder>& impl) - : BpInterface<ICameraService>(impl) - { - } - - // connect to camera service - virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient) - { - Parcel data, reply; - data.writeInterfaceToken(ICameraService::getInterfaceDescriptor()); - data.writeStrongBinder(cameraClient->asBinder()); - remote()->transact(BnCameraService::CONNECT, data, &reply); - return interface_cast<ICamera>(reply.readStrongBinder()); - } -}; - -IMPLEMENT_META_INTERFACE(CameraService, "android.hardware.ICameraService"); - -// ---------------------------------------------------------------------- - -status_t BnCameraService::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - switch(code) { - case CONNECT: { - CHECK_INTERFACE(ICameraService, data, reply); - sp<ICameraClient> cameraClient = interface_cast<ICameraClient>(data.readStrongBinder()); - sp<ICamera> camera = connect(cameraClient); - reply->writeStrongBinder(camera->asBinder()); - return NO_ERROR; - } break; - default: - return BBinder::onTransact(code, data, reply, flags); - } -} - -// ---------------------------------------------------------------------------- - -}; // namespace android - diff --git a/libs/ui/PixelFormat.cpp b/libs/ui/PixelFormat.cpp index b65ed97..9b41804 100644 --- a/libs/ui/PixelFormat.cpp +++ b/libs/ui/PixelFormat.cpp @@ -16,14 +16,17 @@ #include <ui/PixelFormat.h> #include <pixelflinger/format.h> +#include <hardware/hardware.h> namespace android { +static const int COMPONENT_YUV = 0xFF; + size_t PixelFormatInfo::getScanlineSize(unsigned int width) const { size_t size; - if ((components >= 6) && (components <= 8)) { - // YCbCr formats are differents. + if (components == COMPONENT_YUV) { + // YCbCr formats are different. size = (width * bitsPerPixel)>>3; } else { size = width * bytesPerPixel; @@ -53,14 +56,42 @@ status_t getPixelFormatInfo(PixelFormat format, PixelFormatInfo* info) if (info->version != sizeof(PixelFormatInfo)) return INVALID_OPERATION; + // YUV format from the HAL are handled here + switch (format) { + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + case HAL_PIXEL_FORMAT_YCrCb_422_SP: + case HAL_PIXEL_FORMAT_YCbCr_422_P: + case HAL_PIXEL_FORMAT_YCbCr_422_I: + case HAL_PIXEL_FORMAT_CbYCrY_422_I: + info->bitsPerPixel = 16; + goto done; + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: + case HAL_PIXEL_FORMAT_YCrCb_420_SP_TILED: + case HAL_PIXEL_FORMAT_YCbCr_420_P: + case HAL_PIXEL_FORMAT_YCbCr_420_I: + case HAL_PIXEL_FORMAT_CbYCrY_420_I: + info->bitsPerPixel = 12; + done: + info->format = format; + info->components = COMPONENT_YUV; + info->bytesPerPixel = 1; + info->h_alpha = 0; + info->l_alpha = 0; + info->h_red = info->h_green = info->h_blue = 8; + info->l_red = info->l_green = info->l_blue = 0; + return NO_ERROR; + } + size_t numEntries; const GGLFormat *i = gglGetPixelFormatTable(&numEntries) + format; bool valid = uint32_t(format) < numEntries; if (!valid) { return BAD_INDEX; } - - #define COMPONENT(name) \ + + #define COMPONENT(name) \ case GGL_##name: info->components = PixelFormatInfo::name; break; switch (i->components) { @@ -69,9 +100,6 @@ status_t getPixelFormatInfo(PixelFormat format, PixelFormatInfo* info) COMPONENT(RGBA) COMPONENT(LUMINANCE) COMPONENT(LUMINANCE_ALPHA) - COMPONENT(Y_CB_CR_SP) - COMPONENT(Y_CB_CR_P) - COMPONENT(Y_CB_CR_I) default: return BAD_INDEX; } diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp index d21ed57..12db908 100644 --- a/libs/ui/Region.cpp +++ b/libs/ui/Region.cpp @@ -63,16 +63,10 @@ Region::Region(const Rect& rhs) { } -Region::Region(const Parcel& parcel) -{ - status_t err = read(parcel); - LOGE_IF(err<0, "error %s reading Region from parcel", strerror(err)); -} - Region::Region(const void* buffer) { status_t err = read(buffer); - LOGE_IF(err<0, "error %s reading Region from parcel", strerror(err)); + LOGE_IF(err<0, "error %s reading Region from buffer", strerror(err)); } Region::~Region() @@ -532,37 +526,6 @@ void Region::translate(Region& dst, const Region& reg, int dx, int dy) // ---------------------------------------------------------------------------- -status_t Region::write(Parcel& parcel) const -{ -#if VALIDATE_REGIONS - validate(*this, "write(Parcel)"); -#endif - status_t err; - const size_t count = mStorage.size(); - const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect); - void* buffer = parcel.writeInplace(sizeNeeded); - if (!buffer) return NO_MEMORY; - ssize_t written = Region::write(buffer, sizeNeeded); - if (written < 0) return status_t(written); - return NO_ERROR; -} - -status_t Region::read(const Parcel& parcel) -{ - void const* buffer = parcel.readInplace(sizeof(int32_t)); - if (!buffer) return NO_MEMORY; - const size_t count = *static_cast<int32_t const *>(buffer); - void const* dummy = parcel.readInplace((1+count)*sizeof(Rect)); - if (!dummy) return NO_MEMORY; - const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect); - const ssize_t read = Region::read(buffer); - if (read < 0) return status_t(read); -#if VALIDATE_REGIONS - validate(*this, "read(Parcel)"); -#endif - return NO_ERROR; -} - ssize_t Region::write(void* buffer, size_t size) const { #if VALIDATE_REGIONS @@ -570,12 +533,14 @@ ssize_t Region::write(void* buffer, size_t size) const #endif const size_t count = mStorage.size(); const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect); - if (sizeNeeded > size) return NO_MEMORY; - int32_t* const p = static_cast<int32_t*>(buffer); - *p = count; - memcpy(p+1, &mBounds, sizeof(Rect)); - if (count) { - memcpy(p+5, mStorage.array(), count*sizeof(Rect)); + if (buffer != NULL) { + if (sizeNeeded > size) return NO_MEMORY; + int32_t* const p = static_cast<int32_t*>(buffer); + *p = count; + memcpy(p+1, &mBounds, sizeof(Rect)); + if (count) { + memcpy(p+5, mStorage.array(), count*sizeof(Rect)); + } } return ssize_t(sizeNeeded); } diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk index 59409a2..d0eedb4 100644 --- a/libs/utils/Android.mk +++ b/libs/utils/Android.mk @@ -25,6 +25,7 @@ commonSources:= \ CallStack.cpp \ Debug.cpp \ FileMap.cpp \ + Flattenable.cpp \ RefBase.cpp \ ResourceTypes.cpp \ SharedBuffer.cpp \ @@ -75,7 +76,6 @@ include $(CLEAR_VARS) # we have the common sources, plus some device-specific stuff LOCAL_SRC_FILES:= \ $(commonSources) \ - Unicode.cpp \ BackupData.cpp \ BackupHelpers.cpp diff --git a/libs/utils/CharacterData.h b/libs/utils/CharacterData.h deleted file mode 100644 index e931d99..0000000 --- a/libs/utils/CharacterData.h +++ /dev/null @@ -1,730 +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. - */ - -// Automatically generated on 07-11-2006 by make-CharacterDataC -// DO NOT EDIT DIRECTLY -namespace CharacterData { - - // Structure containing an array of ranges - struct Range { - int length; - const uint32_t* array; - }; - - // For Latin1 characters just index into this array to get the index and decomposition - static const uint16_t LATIN1_DATA[] = { - 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, - 0x0001, 0x0002, 0x0003, 0x0002, 0x0004, 0x0003, 0x0001, 0x0001, - 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, - 0x0001, 0x0001, 0x0001, 0x0001, 0x0003, 0x0003, 0x0003, 0x0002, - 0x0005, 0x0006, 0x0006, 0x0007, 0x0008, 0x0007, 0x0006, 0x0006, - 0x0009, 0x000A, 0x0006, 0x000B, 0x000C, 0x000D, 0x000C, 0x000C, - 0x000E, 0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, - 0x0016, 0x0017, 0x000C, 0x0006, 0x0018, 0x0019, 0x001A, 0x0006, - 0x0006, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020, 0x0021, - 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, - 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030, 0x0031, - 0x0032, 0x0033, 0x0034, 0x0035, 0x0006, 0x0036, 0x0037, 0x0038, - 0x0037, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, - 0x0050, 0x0051, 0x0052, 0x0035, 0x0019, 0x0036, 0x0019, 0x0001, - 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0003, 0x0001, 0x0001, - 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, - 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, - 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, - 0x5853, 0x0006, 0x0008, 0x0008, 0x0008, 0x0008, 0x0054, 0x0054, - 0x1037, 0x0054, 0x7855, 0x0056, 0x0019, 0x0057, 0x0054, 0x1037, - 0x0058, 0x0059, 0x785A, 0x785B, 0x1037, 0x105C, 0x0054, 0x0006, - 0x1037, 0x785D, 0x7855, 0x005E, 0x305F, 0x305F, 0x305F, 0x0006, - 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0060, 0x0860, - 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, - 0x0060, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0019, - 0x0060, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0060, 0x0055, - 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0061, 0x0861, - 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, - 0x0061, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0019, - 0x0061, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0061, 0x0862 - }; - - // Each of these arrays is stripped into ranges. In order to build the arrays, each - // codepoint was bit-shifted so that even and odd characters were separated into different - // arrays. The identifier of each array is the top byte after bit-shifting. - // The numbers stored in the array are the bit-shifted codepoint, the decomposition, and an - // index into another array of all possible packed data values. The top 16 bits are the - // codepoint and the bottom 16 are the decomposition and index. The top 5 bits for the decomposition - // and the rest for the index. - static const uint32_t a0[] = { - 0x00800863, 0x00880063, 0x00890863, 0x00930063, 0x00940863, 0x00980864, 0x00991063, 0x009A0863, - 0x009C0055, 0x009D0865, 0x00A01065, 0x00A10065, 0x00A20865, 0x00A50063, 0x00A60863, 0x00A90063, - 0x00AA0863, 0x00B30063, 0x00B40863, 0x00BC0866, 0x00BD0865, 0x00C00055, 0x00C10063, 0x00C30067, - 0x00C40065, 0x00C50068, 0x00C60065, 0x00C70069, 0x00C8006A, 0x00C90065, 0x00CA006B, 0x00CB006C, - 0x00CC0063, 0x00CD006D, 0x00CE006C, 0x00CF006E, 0x00D00863, 0x00D10063, 0x00D3006F, 0x00D40065, - 0x00D50055, 0x00D60063, 0x00D7006F, 0x00D80865, 0x00D90070, 0x00DA0065, 0x00DC0063, 0x00DD0055, - 0x00DE0063, 0x00DF0055, 0x00E00071, 0x00E21072, 0x00E31073, 0x00E41074, 0x00E51072, 0x00E61073, - 0x00E70865, 0x00EF0863, 0x00F20063, 0x00F30863, 0x00F80855, 0x00F91074, 0x00FA0863, 0x00FB0075, - 0x00FC0863, 0x010E0063, 0x010F0863, 0x01100076, 0x01110063, 0x01130863, 0x011A0055, 0x011D0077, - 0x011E0065, 0x011F0077, 0x01200055, 0x01210078, 0x01280055, 0x012A0079, 0x012B007A, 0x012C0055, - 0x0130007A, 0x01310055, 0x0134007B, 0x01350055, 0x0139007C, 0x013A0055, 0x0140007D, 0x01410055, - 0x0144007D, 0x0145007E, 0x01460055, 0x0149007F, 0x014A0080, 0x014B0055, 0x01587881, 0x015D0082, - 0x015E0081, 0x01610037, 0x01630082, 0x01680081, 0x01690037, 0x016C1037, 0x016F0037, 0x01707881, - 0x01730037, 0x01770081, 0x01780037, 0x01800083, 0x01A00883, 0x01A10083, 0x01A20883, 0x01A30083, - 0x01B80078, 0x01BA0837, 0x01BB0078, 0x01BD1081, 0x01BE0078, 0x01BF0806, 0x01C00078, 0x01C21037, - 0x01C30884, 0x01C40885, 0x01C60886, 0x01C70887, 0x01C80855, 0x01C90060, 0x01D10078, 0x01D20060, - 0x01D50860, 0x01D60888, 0x01D70889, 0x01D80855, 0x01D90061, 0x01E1008A, 0x01E20061, 0x01E50861, - 0x01E6088B, 0x01E7088C, 0x01E8108D, 0x01E91077, 0x01EA0877, 0x01EB108E, 0x01EC0063, 0x01F8108F, - 0x01F91090, 0x01FA1091, 0x01FB0019, 0x01FC0065, 0x01FD0063, 0x01FE0055, 0x01FF0077, 0x02000892, - 0x02010092, 0x02060892, 0x02080060, 0x02180061, 0x02280893, 0x02290093, 0x022E0893, 0x02300063, - 0x023B0863, 0x023C0063, 0x02410094, 0x02420083, 0x02440095, 0x02450063, 0x02600077, 0x02610865, - 0x02620065, 0x02680863, 0x026A0063, 0x026B0863, 0x026C0063, 0x026D0863, 0x02700063, 0x02710863, - 0x02740063, 0x02750863, 0x027B0063, 0x027C0863, 0x027D0078, 0x02800063, 0x02880078, 0x02990096, - 0x02AC0078, 0x02AD0097, 0x02B00078, 0x02B10098, 0x02C40078, 0x02C50099, 0x02C60078, 0x02C90083, - 0x02DD0078, 0x02DE0083, 0x02DF009A, 0x02E10083, 0x02E3009A, 0x02E40078, 0x02E8009B, 0x02F60078, - 0x02F8009B, 0x02FA009A, 0x02FB0078, 0x0300009C, 0x03020078, 0x0306000C, 0x03070054, 0x03080083, - 0x030B0078, 0x030F009D, 0x03100078, 0x0311089E, 0x0314009E, 0x031E0078, 0x0320009F, 0x0321009E, - 0x03260083, 0x033000A0, 0x033100A1, 0x033200A2, 0x033300A3, 0x033400A4, 0x03350007, 0x033600A5, - 0x0337009E, 0x03380083, 0x0339009E, 0x033B109E, 0x033D009E, 0x0360089E, 0x0362009E, 0x036A009D, - 0x036B0083, 0x036F0095, 0x03700083, 0x0373009F, 0x03740083, 0x0377009E, 0x0378000E, 0x03790010, - 0x037A0012, 0x037B0014, 0x037C0016, 0x037D009E, 0x037F00A6, 0x0380009D, 0x03870078, 0x0388009E, - 0x03980083, 0x03A60078, 0x03A7009E, 0x03B70078, 0x03C0009E, 0x03D30083, 0x03D90078, 0x04810083, - 0x04820071, 0x049A0871, 0x049B0071, 0x049D0078, 0x049E0083, 0x049F00A7, 0x04A10083, 0x04A500A7, - 0x04A70078, 0x04A80071, 0x04A90083, 0x04AB0078, 0x04AC0871, 0x04B00071, 0x04B10083, 0x04B20097, - 0x04B300A8, 0x04B400A9, 0x04B500AA, 0x04B600AB, 0x04B700AC, 0x04B80097, 0x04B90078, 0x04C100A7, - 0x04C20078, 0x04C30071, 0x04C70078, 0x04C80071, 0x04C90078, 0x04CA0071, 0x04DA0078, 0x04DB0071, - 0x04DD0078, 0x04DE0083, 0x04DF00A7, 0x04E10083, 0x04E30078, 0x04E400A7, 0x04E50078, 0x04E608A7, - 0x04E70071, 0x04E80078, 0x04EE0871, 0x04EF0078, 0x04F00071, 0x04F10083, 0x04F20078, 0x04F300A8, - 0x04F400A9, 0x04F500AA, 0x04F600AB, 0x04F700AC, 0x04F80071, 0x04F90008, 0x04FA00AD, 0x04FB00AE, - 0x04FC00AF, 0x04FD0094, 0x04FE0078, 0x05010083, 0x05020078, 0x05030071, 0x05060078, 0x05080071, - 0x05090078, 0x050A0071, 0x051A0078, 0x051B0871, 0x051C0071, 0x051D0078, 0x051E0083, 0x051F00A7, - 0x05210083, 0x05220078, 0x05240083, 0x05250078, 0x05260083, 0x05270078, 0x052D0871, 0x052E0071, - 0x052F0871, 0x05300078, 0x053300A8, 0x053400A9, 0x053500AA, 0x053600AB, 0x053700AC, 0x05380083, - 0x05390071, 0x053B0078, 0x05410083, 0x05420078, 0x05430071, 0x05470078, 0x05480071, 0x05490078, - 0x054A0071, 0x055A0078, 0x055B0071, 0x055D0078, 0x055E0083, 0x055F00A7, 0x05610083, 0x05630078, - 0x05640083, 0x05650078, 0x056600A7, 0x05670078, 0x05680071, 0x05690078, 0x05700071, 0x05710083, - 0x05720078, 0x057300A8, 0x057400A9, 0x057500AA, 0x057600AB, 0x057700AC, 0x05780078, 0x058100A7, - 0x05820078, 0x05830071, 0x05870078, 0x05880071, 0x05890078, 0x058A0071, 0x059A0078, 0x059B0071, - 0x059D0078, 0x059E0083, 0x059F00A7, 0x05A10083, 0x05A20078, 0x05A408A7, 0x05A50078, 0x05A608A7, - 0x05A70078, 0x05AB0083, 0x05AC0078, 0x05AE0871, 0x05AF0078, 0x05B00071, 0x05B10078, 0x05B300A8, - 0x05B400A9, 0x05B500AA, 0x05B600AB, 0x05B700AC, 0x05B80094, 0x05B90078, 0x05C10083, 0x05C20078, - 0x05C30071, 0x05C60078, 0x05C70071, 0x05CA0871, 0x05CB0078, 0x05CD0071, 0x05D00078, 0x05D20071, - 0x05D30078, 0x05D40071, 0x05D60078, 0x05D70071, 0x05DD0078, 0x05DF00A7, 0x05E00083, 0x05E100A7, - 0x05E20078, 0x05E300A7, 0x05E508A7, 0x05E70078, 0x05F300A8, 0x05F400A9, 0x05F500AA, 0x05F600AB, - 0x05F700AC, 0x05F800B0, 0x05F900B1, 0x05FA0054, 0x05FE0078, 0x060100A7, 0x06020078, 0x06030071, - 0x061A0078, 0x061B0071, 0x061D0078, 0x061F0083, 0x062100A7, 0x06230083, 0x06240883, 0x06250083, - 0x06270078, 0x062B0083, 0x062C0078, 0x06300071, 0x06310078, 0x063300A8, 0x063400A9, 0x063500AA, - 0x063600AB, 0x063700AC, 0x06380078, 0x064100A7, 0x06420078, 0x06430071, 0x065A0078, 0x065B0071, - 0x065D0078, 0x065E0083, 0x065F00A7, 0x066008A7, 0x066100A7, 0x066300B2, 0x066408A7, 0x06660083, - 0x06670078, 0x066B00A7, 0x066C0078, 0x066F0071, 0x06710078, 0x067300A8, 0x067400A9, 0x067500AA, - 0x067600AB, 0x067700AC, 0x06780078, 0x068100A7, 0x06820078, 0x06830071, 0x069D0078, 0x069F00A7, - 0x06A10083, 0x06A20078, 0x06A300A7, 0x06A508A7, 0x06A70078, 0x06B00071, 0x06B10078, 0x06B300A8, - 0x06B400A9, 0x06B500AA, 0x06B600AB, 0x06B700AC, 0x06B80078, 0x06C100A7, 0x06C20078, 0x06C30071, - 0x06CC0078, 0x06CD0071, 0x06D90078, 0x06DA0071, 0x06DE0078, 0x06E00071, 0x06E40078, 0x06E50083, - 0x06E60078, 0x06E800A7, 0x06E90083, 0x06EC00A7, 0x06ED08A7, 0x06F00078, 0x06F900A7, 0x06FA0097, - 0x06FB0078, 0x07010071, 0x071A0083, 0x071E0078, 0x07200071, 0x07230081, 0x07240083, 0x072800A8, - 0x072900A9, 0x072A00AA, 0x072B00AB, 0x072C00AC, 0x072D0097, 0x072E0078, 0x07410071, 0x07430078, - 0x07440071, 0x07460078, 0x074A0071, 0x074C0078, 0x074D0071, 0x07500078, 0x07510071, 0x07520078, - 0x07550071, 0x07560078, 0x07570071, 0x075A0083, 0x075D0078, 0x075E0083, 0x075F0078, 0x07600071, - 0x07630081, 0x07640083, 0x07670078, 0x076800A8, 0x076900A9, 0x076A00AA, 0x076B00AB, 0x076C00AC, - 0x076D0078, 0x076E1071, 0x076F0078, 0x07800071, 0x07810094, 0x07820097, 0x07865897, 0x07870097, - 0x078A0094, 0x078C0083, 0x078D0094, 0x079000A8, 0x079100A9, 0x079200AA, 0x079300AB, 0x079400AC, - 0x079500B3, 0x079A0094, 0x079D00B4, 0x079F00A7, 0x07A00071, 0x07A40078, 0x07A50071, 0x07A90871, - 0x07AA0071, 0x07AE0871, 0x07AF0071, 0x07B60078, 0x07B90083, 0x07BB0883, 0x07BD0083, 0x07C40071, - 0x07C60078, 0x07C80083, 0x07CC0078, 0x07CD0083, 0x07D10883, 0x07D20083, 0x07D60883, 0x07D70083, - 0x07DF0094, 0x07E30083, 0x07E40094, 0x07E70078, 0x07E80097, 0x07E90078, 0x08000071, 0x08110078, - 0x08120071, 0x08130871, 0x08140078, 0x08150071, 0x081600A7, 0x08170083, 0x081A0078, 0x081B0083, - 0x081C00A7, 0x081D0078, 0x082000A8, 0x082100A9, 0x082200AA, 0x082300AB, 0x082400AC, 0x08250097, - 0x08280071, 0x082B00A7, 0x082C0083, 0x082D0078, 0x085000B5, 0x08630078, 0x08680071, 0x087E7881, - 0x087F0078, 0x08800071, 0x08AD0078, 0x08B00071, 0x08D20078, 0x08D40071, 0x08FD0078, 0x09000071, - 0x09270078, 0x09280071, 0x092F0078, 0x09300071, 0x09470078, 0x09480071, 0x095B0078, 0x095C0071, - 0x09630078, 0x09640071, 0x098B0078, 0x098C0071, 0x09AE0078, 0x09B00094, 0x09B10097, 0x09B500B6, - 0x09B600B7, 0x09B700B8, 0x09B800B9, 0x09B900B0, 0x09BA00BA, 0x09BB00BB, 0x09BC00BC, 0x09BD00BD, - 0x09BE00BE, 0x09BF0078, 0x09C00071, 0x09C80054, 0x09CD0078, 0x09D00071, 0x09FB0078, 0x0A010071, - 0x0B370097, 0x0B380071, 0x0B3C0078, 0x0B400005, 0x0B410071, 0x0B4E00BF, 0x0B4F0078, 0x0B500071, - 0x0B760097, 0x0B7700C0, 0x0B7800C1, 0x0B790078, 0x0B800071, 0x0B890083, 0x0B8B0078, 0x0B900071, - 0x0B990083, 0x0B9B0097, 0x0B9C0078, 0x0BA00071, 0x0BA90083, 0x0BAA0078, 0x0BB00071, 0x0BB90083, - 0x0BBA0078, 0x0BC00071, 0x0BDA00C2, 0x0BDB00A7, 0x0BDC0083, 0x0BDF00A7, 0x0BE30083, 0x0BE400A7, - 0x0BE50083, 0x0BEA0097, 0x0BEE0071, 0x0BEF0078, 0x0BF000A8, 0x0BF100A9, 0x0BF200AA, 0x0BF300AB, - 0x0BF400AC, 0x0BF50078, 0x0BF800C3, 0x0BF900C4, 0x0BFA00C5, 0x0BFB00C6, 0x0BFC00C7, 0x0BFD0078, - 0x0C000006, 0x0C030099, 0x0C040006, 0x0C060083, 0x0C070005, 0x0C0800A8, 0x0C0900A9, 0x0C0A00AA, - 0x0C0B00AB, 0x0C0C00AC, 0x0C0D0078, 0x0C100071, 0x0C3C0078, 0x0C400071, 0x0C550078, 0x0C800071, - 0x0C8F0078, 0x0C900083, 0x0C9200A7, 0x0C940083, 0x0C9500C8, 0x0C960078, 0x0C9800A7, 0x0C990083, - 0x0C9A00A7, 0x0C9D0083, 0x0C9E0078, 0x0CA00054, 0x0CA10078, 0x0CA20006, 0x0CA300A8, 0x0CA400A9, - 0x0CA500AA, 0x0CA600AB, 0x0CA700AC, 0x0CA80071, 0x0CB70078, 0x0CB80071, 0x0CBB0078, 0x0CC00071, - 0x0CD50078, 0x0CD800A7, 0x0CE10071, 0x0CE400A7, 0x0CE50078, 0x0CE800A8, 0x0CE900A9, 0x0CEA00AA, - 0x0CEB00AB, 0x0CEC00AC, 0x0CED0078, 0x0CEF0006, 0x0CF00054, 0x0D000071, 0x0D0C0083, 0x0D0D00A7, - 0x0D0E0078, 0x0D0F0097, 0x0D100078, 0x0E800055, 0x0E967881, 0x0EA70081, 0x0EA87881, 0x0EB17055, - 0x0EB60055, 0x0EBC7881, 0x0EBD0055, 0x0ECE7881, 0x0EE00083, 0x0EE20078, 0x0F000863, 0x0F4B0855, - 0x0F4D1055, 0x0F4E0078, 0x0F500863, 0x0F7D0078, 0x0F8008C9, 0x0F8408CA, 0x0F8808C9, 0x0F8B0078, - 0x0F8C08CA, 0x0F8F0078, 0x0F9008C9, 0x0F9408CA, 0x0F9808C9, 0x0F9C08CA, 0x0FA008C9, 0x0FA30078, - 0x0FA408CA, 0x0FA70078, 0x0FA80855, 0x0FAC0078, 0x0FB008C9, 0x0FB408CA, 0x0FB808CB, 0x0FB908CC, - 0x0FBB08CD, 0x0FBC08CE, 0x0FBD08CF, 0x0FBE08D0, 0x0FBF0078, 0x0FC008C9, 0x0FC408D1, 0x0FC808C9, - 0x0FCC08D1, 0x0FD008C9, 0x0FD408D1, 0x0FD808C9, 0x0FD90855, 0x0FDC08CA, 0x0FDD08D2, 0x0FDE08D3, - 0x0FDF08D4, 0x0FE01037, 0x0FE10855, 0x0FE408D5, 0x0FE608D3, 0x0FE70837, 0x0FE808C9, 0x0FE90855, - 0x0FEA0078, 0x0FEB0855, 0x0FEC08CA, 0x0FED08D6, 0x0FEE0078, 0x0FEF0837, 0x0FF008C9, 0x0FF10855, - 0x0FF408CA, 0x0FF508D7, 0x0FF608D8, 0x0FF70837, 0x0FF80078, 0x0FF90855, 0x0FFC08D9, 0x0FFD08DA, - 0x0FFE08D3, 0x0FFF1037, 0x10000805, 0x10011005, 0x10060057, 0x100700C2, 0x10080099, 0x100B0006, - 0x100C00DB, 0x100D00B4, 0x100E00DB, 0x100F00B4, 0x10100006, 0x10121006, 0x101400DC, 0x101500DD, - 0x101600DE, 0x101700DF, 0x10180007, 0x101A1007, 0x101B1006, 0x101C0006, 0x101D00E0, 0x101E1006, - 0x10200038, 0x10210006, 0x102200E1, 0x1023000A, 0x10241006, 0x10250006, 0x10290019, 0x102A0038, - 0x102B0006, 0x10300057, 0x10320078, 0x10350057, 0x103878E2, 0x10390078, 0x103A78E3, 0x103B78E4, - 0x103C78E5, 0x103D780B, 0x103E7819, 0x103F780A, 0x104070E2, 0x1041705A, 0x104270E3, 0x104370E4, - 0x104470E5, 0x1045700B, 0x10467019, 0x1047700A, 0x10487081, 0x104B0078, 0x10500008, 0x10541008, - 0x10550008, 0x105B0078, 0x10680083, 0x106F0095, 0x10730083, 0x10760078, 0x10801054, 0x10812877, - 0x10820054, 0x10831054, 0x10840054, 0x10852855, 0x10862877, 0x10872855, 0x10882877, 0x108A0054, - 0x108B1054, 0x108C0054, 0x108D2877, 0x108F0054, 0x10907854, 0x10922877, 0x109308E6, 0x10942877, - 0x109508E7, 0x10962877, 0x10970058, 0x10982877, 0x10990054, 0x109A2855, 0x109B1071, 0x109D0054, - 0x109E2855, 0x109F2877, 0x10A028E8, 0x10A10019, 0x10A32855, 0x10A50054, 0x10A70078, 0x10AA305F, - 0x10B010E9, 0x10B110EA, 0x10B210EB, 0x10B310EC, 0x10B410ED, 0x10B510EE, 0x10B610EF, 0x10B710F0, - 0x10B810F1, 0x10B910F2, 0x10BA10F3, 0x10BB10F4, 0x10BC10F5, 0x10BD10F6, 0x10BE10F7, 0x10BF10F8, - 0x10C000F9, 0x10C100FA, 0x10C20078, 0x10C80019, 0x10CB0054, 0x10CD0819, 0x10CE0054, 0x10D00019, - 0x10D10054, 0x10D30019, 0x10D40054, 0x10D70819, 0x10D80054, 0x10E70819, 0x10E80054, 0x10E90019, - 0x10EB0054, 0x10FA0019, 0x110100E8, 0x110208E8, 0x11030019, 0x110400FB, 0x110608FC, 0x11070019, - 0x1109000B, 0x110A0019, 0x110B00E8, 0x110C0019, 0x110D00E8, 0x110F0019, 0x111000E8, 0x111208E8, - 0x11140019, 0x111610E8, 0x111700E8, 0x111810E8, 0x111900E8, 0x111A0019, 0x111E00FD, 0x111F00E8, - 0x112208E8, 0x112300E8, 0x11270019, 0x112900FD, 0x112B0019, 0x113008E8, 0x113200FD, 0x11360019, - 0x113708FD, 0x113900FD, 0x113A08FD, 0x113B00FD, 0x113C08FD, 0x113D00FD, 0x114008FD, 0x114100FD, - 0x114208FD, 0x114300FD, 0x114408FD, 0x114500FD, 0x114600E8, 0x11470019, 0x114800FE, 0x114A0019, - 0x114C00FF, 0x114D0019, 0x115100FD, 0x11520019, 0x11530100, 0x11540101, 0x115500E8, 0x115608E8, - 0x115800FD, 0x115C00E8, 0x115D0019, 0x115F00E8, 0x11600019, 0x116500FE, 0x11670019, 0x116800FD, - 0x11690019, 0x116B00FD, 0x117008FD, 0x117200FD, 0x117508FD, 0x11770019, 0x117800FD, 0x11790102, - 0x117B0103, 0x117C00E8, 0x117D0104, 0x117F0105, 0x11800054, 0x118400FD, 0x11860054, 0x119000E8, - 0x11910054, 0x1195080A, 0x11960054, 0x119B0094, 0x11BE0019, 0x11BF0054, 0x11CE0019, 0x11DA00B4, - 0x11DB0006, 0x11DC0054, 0x11EE0078, 0x12000054, 0x12140078, 0x12200054, 0x12260078, 0x12301906, - 0x12311907, 0x12321908, 0x12331909, 0x1234190A, 0x1235190B, 0x1236190C, 0x1237190D, 0x1238190E, - 0x1239190F, 0x123A1106, 0x123B1107, 0x123C1108, 0x123D1109, 0x123E110A, 0x123F110B, 0x1240110C, - 0x1241110D, 0x1242110E, 0x1243110F, 0x1244105D, 0x1245105B, 0x12461110, 0x12471111, 0x12481112, - 0x12491113, 0x124A1114, 0x124B1115, 0x124C1116, 0x124D1117, 0x124E1094, 0x125B1918, 0x12681919, - 0x127518C3, 0x1276011A, 0x1277011B, 0x1278011C, 0x1279011D, 0x127A011E, 0x127B00C4, 0x127C00C5, - 0x127D00C6, 0x127E00C7, 0x127F011F, 0x12800054, 0x12FC0019, 0x13000054, 0x134F0078, 0x13500054, - 0x13560094, 0x13570054, 0x13590078, 0x13810054, 0x13850078, 0x13860054, 0x13940078, 0x13950054, - 0x13A60078, 0x13A80054, 0x13AA0078, 0x13AB0054, 0x13B00078, 0x13B10054, 0x13B40009, 0x13BB0106, - 0x13BC0107, 0x13BD0108, 0x13BE0109, 0x13BF010A, 0x13C00106, 0x13C10107, 0x13C20108, 0x13C30109, - 0x13C4010A, 0x13C50106, 0x13C60107, 0x13C70108, 0x13C80109, 0x13C9010A, 0x13CA0054, 0x13CB0078, - 0x13CC0054, 0x13D80078, 0x13D90054, 0x13E000E8, 0x13E10019, 0x13E200FE, 0x13E3000A, 0x13E40078, - 0x13E80019, 0x13EA00E8, 0x13EB00FE, 0x13EC0019, 0x13EE00E8, 0x13EF00FE, 0x13F00019, 0x13F100FD, - 0x13F30009, 0x13F60078, 0x13F80019, 0x14000094, 0x14800019, 0x14C2000A, 0x14C70120, 0x14C80121, - 0x14C9000A, 0x14CD0019, 0x14CE00E8, 0x14D80019, 0x14DC0122, 0x14DD0019, 0x14E000FD, 0x14E100E8, - 0x14E200FD, 0x14E30019, 0x14E700E8, 0x14E800FE, 0x14EA00FD, 0x14EB0019, 0x14EC0009, 0x14EE00E8, - 0x14EF0019, 0x14F200E8, 0x14F30019, 0x14F400E8, 0x14F50019, 0x14FA00E8, 0x14FC00FD, 0x14FD0019, - 0x14FE0009, 0x14FF0019, 0x150500E8, 0x150610E8, 0x150700E8, 0x15110019, 0x151200E8, 0x15140019, - 0x151600FE, 0x15180019, 0x151A00FD, 0x151B0019, 0x151E00FD, 0x151F00E8, 0x15200019, 0x152C00E8, - 0x152D0019, 0x153200FD, 0x15330019, 0x153500E8, 0x15370019, 0x153800E8, 0x15390019, 0x153A10E8, - 0x153B1019, 0x153C0019, 0x153D00FE, 0x153E00E8, 0x153F00FE, 0x154300E8, 0x154600FE, 0x154700E8, - 0x154900FE, 0x154F00E8, 0x155100FE, 0x15520019, 0x155300FD, 0x15570019, 0x155800FE, 0x155900E8, - 0x155A00FE, 0x155B00E8, 0x155E00FE, 0x156400E8, 0x156700FE, 0x156C0019, 0x156E08E8, 0x156F0123, - 0x15700019, 0x157100E8, 0x15720124, 0x157300E8, 0x15740019, 0x157600FD, 0x157700E8, 0x15780019, - 0x157C00FE, 0x157E0019, 0x15800054, 0x158A0078, 0x16000096, 0x16180098, 0x16300078, 0x16400063, - 0x16720055, 0x16730054, 0x16760078, 0x167D0006, 0x16800125, 0x16930078, 0x16980071, 0x16B30078, - 0x16C00071, 0x16CC0078, 0x16D00071, 0x16F00078, 0x17000006, 0x17010126, 0x17030006, 0x170500E0, - 0x17060126, 0x17070006, 0x170C0078, 0x170E0126, 0x170F0078, 0x17400054, 0x174D0078, 0x174E0054, - 0x177A0078, 0x17801054, 0x17EB0078, 0x17F80054, 0x17FE0078, 0x18008805, 0x18010006, 0x18020054, - 0x18030071, 0x18040009, 0x18090054, 0x180A0009, 0x180E0099, 0x180F00BF, 0x18100054, 0x18110127, - 0x18120128, 0x18130129, 0x1814012A, 0x18150083, 0x18180099, 0x18190081, 0x181B1054, 0x181C112B, - 0x181D112C, 0x181E0071, 0x181F0054, 0x18200078, 0x18210071, 0x18260871, 0x18320071, 0x18380871, - 0x18390071, 0x183A0871, 0x183C0071, 0x183D0871, 0x183F0071, 0x184A0871, 0x184B0071, 0x184C0078, - 0x184D0083, 0x184E1037, 0x184F0881, 0x18500099, 0x18510071, 0x18560871, 0x18620071, 0x18680871, - 0x18690071, 0x186A0871, 0x186C0071, 0x186D0871, 0x186F0071, 0x187A0871, 0x187B0071, 0x187C0871, - 0x187E0081, 0x187F0881, 0x18800078, 0x18830071, 0x18970078, 0x18991071, 0x18C80094, 0x18C978AD, - 0x18CA78AE, 0x18CB7894, 0x18D00071, 0x18DC0078, 0x18E00054, 0x18E80078, 0x18F80071, 0x19001094, - 0x190F1054, 0x191010AD, 0x191110AE, 0x1912112D, 0x1913112E, 0x1914112F, 0x19151094, 0x19220078, - 0x19286854, 0x19291930, 0x192A1931, 0x192B1932, 0x192C1933, 0x192D1934, 0x192E1935, 0x192F1936, - 0x19301894, 0x193E1854, 0x194018AD, 0x194118AE, 0x1942192D, 0x1943192E, 0x1944192F, 0x19451894, - 0x19591937, 0x195A1938, 0x195B1939, 0x195C193A, 0x195D193B, 0x195E193C, 0x195F193D, 0x19601094, - 0x19666854, 0x19681894, 0x19806894, 0x19AC1094, 0x19B96894, 0x19BC6854, 0x19BE6894, 0x19EF6854, - 0x19F01094, 0x1A000071, 0x26DB0078, 0x26E00054, 0x27000071, 0x4FDE0078, 0x50000071, 0x52470078, - 0x52480054, 0x52640078, 0x53800037, 0x538C0078, 0x54000071, 0x540100C8, 0x54020071, 0x54030083, - 0x54040071, 0x541200A7, 0x54130083, 0x54140054, 0x54160078, 0x56000071, 0x6BD20078, 0x6C00013E, - 0x7000013F, 0x7C800871, 0x7D070071, 0x7D080871, 0x7D0A0071, 0x7D0B0871, 0x7D120071, 0x7D130871, - 0x7D140071, 0x7D150871, 0x7D170078, 0x7D180871, 0x7D360078, 0x7D380871, 0x7D6D0078, 0x7D801055, - 0x7D840078, 0x7D8A1055, 0x7D8C0078, 0x7D8F0083, 0x7D90289B, 0x7D95089B, 0x7DA10078, 0x7DA2089B, - 0x7DA8409E, 0x7DAA389E, 0x7DAB409E, 0x7DAC389E, 0x7DAD409E, 0x7DAE389E, 0x7DAF409E, 0x7DB0389E, - 0x7DB1409E, 0x7DB2389E, 0x7DB3409E, 0x7DB4389E, 0x7DB5409E, 0x7DB6389E, 0x7DB7409E, 0x7DB8389E, - 0x7DB9409E, 0x7DBA389E, 0x7DBB409E, 0x7DBC389E, 0x7DBD409E, 0x7DBE389E, 0x7DBF409E, 0x7DC0389E, - 0x7DC1409E, 0x7DC8389E, 0x7DC9409E, 0x7DCA389E, 0x7DCB409E, 0x7DCC389E, 0x7DCD409E, 0x7DCE389E, - 0x7DCF409E, 0x7DD1389E, 0x7DD2409E, 0x7DD4389E, 0x7DD5409E, 0x7DD6389E, 0x7DD7409E, 0x7DD90078, - 0x7DEA209E, 0x7DEB489E, 0x7DEC209E, 0x7DEF409E, 0x7DF3389E, 0x7DF5409E, 0x7DFC389E, 0x7DFD209E, - 0x7DFE409E, 0x7DFF389E, 0x7E00409E, 0x7E32209E, 0x7E4C389E, 0x7E70489E, 0x7E7B409E, 0x7E89209E, - 0x7E97389E, 0x7E9A489E, 0x7E9E209E, 0x7E9F00B4, 0x7EA00078, 0x7EA8389E, 0x7EAC209E, 0x7EAE389E, - 0x7EAF209E, 0x7EB0389E, 0x7EB1209E, 0x7EB4389E, 0x7EB5209E, 0x7EB8389E, 0x7EBA209E, 0x7EC3389E, - 0x7EC80078, 0x7EC9389E, 0x7ECB209E, 0x7ECC389E, 0x7ECD209E, 0x7EDA389E, 0x7EDB209E, 0x7EDC389E, - 0x7EDE209E, 0x7EE2389E, 0x7EE3209E, 0x7EE40078, 0x7EF8409E, 0x7EFE4140, 0x7EFF0078, 0x7F000083, - 0x7F088006, 0x7F0C80BF, 0x7F0D0078, 0x7F100083, 0x7F120078, 0x7F188006, 0x7F198099, 0x7F1A8038, - 0x7F1B80BF, 0x7F230006, 0x7F2480BF, 0x7F251006, 0x7F271038, 0x7F28600C, 0x7F2A6006, 0x7F2C6099, - 0x7F2D60BF, 0x7F306006, 0x7F31600B, 0x7F326019, 0x7F346006, 0x7F356007, 0x7F360078, 0x7F38409E, - 0x7F41209E, 0x7F46489E, 0x7F47209E, 0x7F49489E, 0x7F4A209E, 0x7F4C489E, 0x7F4D209E, 0x7F4E489E, - 0x7F4F209E, 0x7F50489E, 0x7F51209E, 0x7F52489E, 0x7F53209E, 0x7F54489E, 0x7F55209E, 0x7F5A489E, - 0x7F5B209E, 0x7F5C489E, 0x7F5D209E, 0x7F5E489E, 0x7F5F209E, 0x7F60489E, 0x7F61209E, 0x7F62489E, - 0x7F63209E, 0x7F64489E, 0x7F65209E, 0x7F66489E, 0x7F67209E, 0x7F68489E, 0x7F69209E, 0x7F6A489E, - 0x7F6B209E, 0x7F6C489E, 0x7F6D209E, 0x7F6E489E, 0x7F6F209E, 0x7F70489E, 0x7F71209E, 0x7F72489E, - 0x7F73209E, 0x7F74489E, 0x7F75209E, 0x7F76489E, 0x7F77209E, 0x7F7A489E, 0x7F7B209E, 0x7F7F0078, - 0x7F818806, 0x7F828808, 0x7F838806, 0x7F848809, 0x7F858806, 0x7F86880C, 0x7F88880E, 0x7F898810, - 0x7F8A8812, 0x7F8B8814, 0x7F8C8816, 0x7F8D880C, 0x7F8E8818, 0x7F8F881A, 0x7F908806, 0x7F918860, - 0x7F9E8806, 0x7F9F8837, 0x7FA18861, 0x7FAE8819, 0x7FB0880A, 0x7FB15009, 0x7FB25006, 0x7FB35071, - 0x7FB85081, 0x7FB95071, 0x7FCF5081, 0x7FD05071, 0x7FE00078, 0x7FE15071, 0x7FE40078, 0x7FE55071, - 0x7FE80078, 0x7FE95071, 0x7FEC0078, 0x7FED5071, 0x7FEF0078, 0x7FF08808, 0x7FF18819, 0x7FF28854, - 0x7FF38808, 0x7FF45054, 0x7FF55019, 0x7FF75054, 0x7FF80078, 0x7FFD0141, 0x7FFE0054, 0x7FFF0078, - 0x80000071, 0x80060078, 0x80070071, 0x801F0078, 0x80200071, 0x80270078, 0x80280071, 0x802F0078, - 0x80400071, 0x807E0078, 0x80800097, 0x80810094, 0x80820078, 0x808400B6, 0x808500B7, 0x808600B8, - 0x808700B9, 0x808800B0, 0x808900BA, 0x808A00BB, 0x808B00BC, 0x808C00BD, 0x808D0142, 0x808E0143, - 0x808F0144, 0x80900145, 0x809100B1, 0x80920146, 0x80930147, 0x80940148, 0x80950149, 0x8096014A, - 0x8097014B, 0x8098014C, 0x8099014D, 0x809A0078, 0x809C0094, 0x80A0014E, 0x80A1014F, 0x80A20150, - 0x80A30151, 0x80A40152, 0x80A50150, 0x80A60153, 0x80A70151, 0x80A80154, 0x80A90155, 0x80AA0156, - 0x80AB0157, 0x80AC014F, 0x80AE0158, 0x80B00154, 0x80B30150, 0x80B50155, 0x80B60153, 0x80B90151, - 0x80BA0150, 0x80BB005F, 0x80BD0054, 0x80C500C3, 0x80C60078, 0x81800071, 0x819000AD, 0x819100B0, - 0x81920078, 0x81980071, 0x81A50159, 0x81A60078, 0x81C00071, 0x81CF0078, 0x81D00071, 0x81E20078, - 0x81E40071, 0x81E80094, 0x81E90158, 0x81EA015A, 0x81EB0078, 0x8200015B, 0x8214015C, 0x82280071, - 0x824F0078, 0x825000A8, 0x825100A9, 0x825200AA, 0x825300AB, 0x825400AC, 0x82550078, 0x8400009B, - 0x84030078, 0x8404009B, 0x841B0078, 0x841C009B, 0x841D0078, 0x841E009B, 0x841F0078, 0x8500009B, - 0x85010083, 0x85020078, 0x85030083, 0x85040078, 0x85060083, 0x8508009B, 0x850A0078, 0x850B009B, - 0x850C0078, 0x850D009B, 0x851A0078, 0x851C0083, 0x851E0078, 0x8520015D, 0x8521015E, 0x8522015F, - 0x85230160, 0x85240078, 0x8528009A, 0x852D0078, 0xE8000094, 0xE87B0078, 0xE8800094, 0xE8940078, - 0xE8950094, 0xE8AF0894, 0xE8B300A7, 0xE8B40083, 0xE8B50094, 0xE8B700A7, 0xE8BA0057, 0xE8BE0083, - 0xE8C20094, 0xE8C30083, 0xE8C60094, 0xE8D50083, 0xE8D70094, 0xE8DE0894, 0xE8E10094, 0xE8EF0078, - 0xE9000054, 0xE9210083, 0xE9230078, 0xE9800054, 0xE9AC0078, 0xEA002877, 0xEA0D2855, 0xEA1A2877, - 0xEA272855, 0xEA342877, 0xEA412855, 0xEA4E2877, 0xEA500078, 0xEA512877, 0xEA520078, 0xEA532877, - 0xEA540078, 0xEA552877, 0xEA5B2855, 0xEA5D0078, 0xEA5F2855, 0xEA620078, 0xEA632855, 0xEA682877, - 0xEA752855, 0xEA822877, 0xEA830078, 0xEA842877, 0xEA860078, 0xEA872877, 0xEA8F2855, 0xEA9C2877, - 0xEA9D0078, 0xEA9E2877, 0xEAA40078, 0xEAA52877, 0xEAA92855, 0xEAB62877, 0xEAC32855, 0xEAD02877, - 0xEADD2855, 0xEAEA2877, 0xEAF72855, 0xEB042877, 0xEB112855, 0xEB1E2877, 0xEB2B2855, 0xEB382877, - 0xEB452855, 0xEB530078, 0xEB542877, 0xEB612855, 0xEB712877, 0xEB7E2855, 0xEB8E2877, 0xEB9B2855, - 0xEBAB2877, 0xEBB82855, 0xEBC82877, 0xEBD52855, 0xEBE50078, 0xEBE7280E, 0xEBE82810, 0xEBE92812, - 0xEBEA2814, 0xEBEB2816, 0xEBEC280E, 0xEBED2810, 0xEBEE2812, 0xEBEF2814, 0xEBF02816, 0xEBF1280E, - 0xEBF22810, 0xEBF32812, 0xEBF42814, 0xEBF52816, 0xEBF6280E, 0xEBF72810, 0xEBF82812, 0xEBF92814, - 0xEBFA2816, 0xEBFB280E, 0xEBFC2810, 0xEBFD2812, 0xEBFE2814, 0xEBFF2816, 0xEC000078 - }; - - static const uint32_t a1[] = { - 0x00000071, 0x536C0078, 0x7C000871, 0x7D0F0078 - }; - - static const uint32_t a7[] = { - 0x00100057, 0x00400078, 0x00800083, 0x00F80078, 0x8000013F, 0xFFFF0078 - }; - - static const uint32_t a8[] = { - 0x0000013F, 0x7FFF0078 - }; - - static const uint32_t a16[] = { - 0x00800865, 0x00880065, 0x00890865, 0x00930065, 0x00940865, 0x00980161, 0x00991065, 0x009A0865, - 0x009C0863, 0x009F1063, 0x00A00063, 0x00A10863, 0x00A41055, 0x00A50065, 0x00A60865, 0x00A90065, - 0x00AA0865, 0x00B30065, 0x00B40865, 0x00BC0863, 0x00BF1162, 0x00C00163, 0x00C10065, 0x00C30063, - 0x00C40068, 0x00C50063, 0x00C60055, 0x00C70164, 0x00C80063, 0x00C90068, 0x00CA0165, 0x00CB0166, - 0x00CC0065, 0x00CD0055, 0x00CE0167, 0x00CF0168, 0x00D00865, 0x00D10065, 0x00D30063, 0x00D4006F, - 0x00D50055, 0x00D60065, 0x00D70863, 0x00D80070, 0x00D90063, 0x00DB0169, 0x00DC0065, 0x00DD0071, - 0x00DE0065, 0x00DF016A, 0x00E00071, 0x00E21074, 0x00E31072, 0x00E41073, 0x00E51074, 0x00E60863, - 0x00EE016B, 0x00EF0865, 0x00F20065, 0x00F30865, 0x00F81072, 0x00F91073, 0x00FA0865, 0x00FB016C, - 0x00FC0865, 0x010E0065, 0x010F0865, 0x01100055, 0x01110065, 0x01130865, 0x011A0055, 0x011D0063, - 0x011E016D, 0x011F0055, 0x0120016E, 0x01210078, 0x01280055, 0x0129016F, 0x012A0055, 0x012B007A, - 0x012C0170, 0x012D0171, 0x012E0055, 0x01310172, 0x01320055, 0x01340173, 0x01350055, 0x01370173, - 0x01380055, 0x013A0174, 0x013B0055, 0x0141007D, 0x01420055, 0x0145007E, 0x01460055, 0x01587881, - 0x015C0082, 0x015D0081, 0x01610037, 0x01630082, 0x01680081, 0x01690037, 0x016C1037, 0x016F0037, - 0x01707881, 0x01720037, 0x01800083, 0x01A00883, 0x01A20175, 0x01A30083, 0x01B80078, 0x01BA0037, - 0x01BB0078, 0x01C20837, 0x01C30806, 0x01C40885, 0x01C50078, 0x01C70887, 0x01C80060, 0x01D50860, - 0x01D60889, 0x01D80061, 0x01E50861, 0x01E6088C, 0x01E70078, 0x01E81176, 0x01E90877, 0x01EA1177, - 0x01EB0055, 0x01EC0065, 0x01F81093, 0x01F90055, 0x01FA1178, 0x01FB0063, 0x01FC10D8, 0x01FD0065, - 0x01FE0077, 0x02000892, 0x02020092, 0x02030892, 0x02040092, 0x02060892, 0x02070092, 0x02080060, - 0x020C0860, 0x020D0060, 0x02180061, 0x021C0861, 0x021D0061, 0x02280893, 0x022A0093, 0x022B0893, - 0x022C0093, 0x022E0893, 0x022F0093, 0x02300065, 0x023B0865, 0x023C0065, 0x02410083, 0x02430078, - 0x02440095, 0x02450065, 0x02600863, 0x02610063, 0x02670078, 0x02680865, 0x026A0065, 0x026B0865, - 0x026C0065, 0x026D0865, 0x02700065, 0x02710865, 0x02740065, 0x02750865, 0x027B0065, 0x027C0865, - 0x027D0078, 0x02800065, 0x02880078, 0x02980096, 0x02AB0078, 0x02AC0081, 0x02AD0097, 0x02B00098, - 0x02C31055, 0x02C40097, 0x02C50078, 0x02C80083, 0x02E1009A, 0x02E20083, 0x02E40078, 0x02E8009B, - 0x02F50078, 0x02F8009B, 0x02F9009A, 0x02FA0078, 0x0300009C, 0x03020078, 0x03050140, 0x0306009D, - 0x03070054, 0x03080083, 0x030B0078, 0x030D009D, 0x030E0078, 0x030F009D, 0x0310009E, 0x0311089E, - 0x0313009E, 0x031D0078, 0x0320009E, 0x03250083, 0x032F0078, 0x03300179, 0x0331017A, 0x0332017B, - 0x0333017C, 0x0334017D, 0x033500A5, 0x0336009D, 0x0337009E, 0x033A109E, 0x033C009E, 0x0369089E, - 0x036A009E, 0x036B0083, 0x036E009C, 0x036F0083, 0x0372009F, 0x03730083, 0x03740054, 0x03750083, - 0x0377009E, 0x0378000F, 0x03790011, 0x037A0013, 0x037B0015, 0x037C0017, 0x037D009E, 0x037E00A6, - 0x037F009E, 0x0380009D, 0x03870057, 0x03880083, 0x0389009E, 0x03980083, 0x03A50078, 0x03A6009E, - 0x03B70078, 0x03C0009E, 0x03D30083, 0x03D8009E, 0x03D90078, 0x04800083, 0x048100A7, 0x04820071, - 0x04940871, 0x04950071, 0x04980871, 0x04990071, 0x049D0078, 0x049E0071, 0x049F00A7, 0x04A00083, - 0x04A400A7, 0x04A60083, 0x04A70078, 0x04A80083, 0x04AA0078, 0x04AC0871, 0x04B00071, 0x04B10083, - 0x04B20097, 0x04B3017E, 0x04B4017F, 0x04B50180, 0x04B60181, 0x04B70182, 0x04B80078, 0x04BE0071, - 0x04BF0078, 0x04C00083, 0x04C100A7, 0x04C20071, 0x04C60078, 0x04C70071, 0x04C80078, 0x04C90071, - 0x04D40078, 0x04D50071, 0x04D80078, 0x04DB0071, 0x04DD0078, 0x04DE0071, 0x04DF00A7, 0x04E00083, - 0x04E20078, 0x04E300A7, 0x04E40078, 0x04E508A7, 0x04E60083, 0x04E70078, 0x04EB00A7, 0x04EC0078, - 0x04EE0871, 0x04F00071, 0x04F10083, 0x04F20078, 0x04F3017E, 0x04F4017F, 0x04F50180, 0x04F60181, - 0x04F70182, 0x04F80071, 0x04F90008, 0x04FA00B6, 0x04FB00B7, 0x04FC0183, 0x04FD0078, 0x05000083, - 0x050100A7, 0x05020071, 0x05050078, 0x05070071, 0x05080078, 0x05090071, 0x05140078, 0x05150071, - 0x05180078, 0x05190871, 0x051A0071, 0x051B0078, 0x051C0071, 0x051D0078, 0x051F00A7, 0x05200083, - 0x05210078, 0x05230083, 0x05240078, 0x05250083, 0x05270078, 0x052C0871, 0x052E0078, 0x0533017E, - 0x0534017F, 0x05350180, 0x05360181, 0x05370182, 0x05380083, 0x05390071, 0x053A0078, 0x05400083, - 0x054100A7, 0x05420071, 0x05540078, 0x05550071, 0x05580078, 0x05590071, 0x055D0078, 0x055E0071, - 0x055F00A7, 0x05600083, 0x056400A7, 0x05660083, 0x05670078, 0x05700071, 0x05710083, 0x05720078, - 0x0573017E, 0x0574017F, 0x05750180, 0x05760181, 0x05770182, 0x05780008, 0x05790078, 0x05800083, - 0x058100A7, 0x05820071, 0x05860078, 0x05870071, 0x05880078, 0x05890071, 0x05940078, 0x05950071, - 0x05980078, 0x05990071, 0x059D0078, 0x059E0071, 0x059F0083, 0x05A20078, 0x05A300A7, 0x05A40078, - 0x05A508A7, 0x05A60083, 0x05A70078, 0x05AB00A7, 0x05AC0078, 0x05AE0871, 0x05AF0071, 0x05B10078, - 0x05B3017E, 0x05B4017F, 0x05B50180, 0x05B60181, 0x05B70182, 0x05B80071, 0x05B90078, 0x05C10071, - 0x05C50078, 0x05C70071, 0x05C80078, 0x05C90071, 0x05CB0078, 0x05CC0071, 0x05CD0078, 0x05CF0071, - 0x05D00078, 0x05D10071, 0x05D20078, 0x05D40071, 0x05D50078, 0x05D70071, 0x05DD0078, 0x05DF00A7, - 0x05E10078, 0x05E300A7, 0x05E40078, 0x05E508A7, 0x05E60083, 0x05E70078, 0x05EB00A7, 0x05EC0078, - 0x05F3017E, 0x05F4017F, 0x05F50180, 0x05F60181, 0x05F70182, 0x05F80184, 0x05F90054, 0x05FC0008, - 0x05FD0078, 0x060000A7, 0x06020071, 0x06060078, 0x06070071, 0x06080078, 0x06090071, 0x06140078, - 0x06150071, 0x061D0078, 0x061F0083, 0x062000A7, 0x06220078, 0x06230083, 0x06240078, 0x06250083, - 0x06270078, 0x062A0083, 0x062B0078, 0x06300071, 0x06310078, 0x0633017E, 0x0634017F, 0x06350180, - 0x06360181, 0x06370182, 0x06380078, 0x064100A7, 0x06420071, 0x06460078, 0x06470071, 0x06480078, - 0x06490071, 0x06540078, 0x06550071, 0x065D0078, 0x065E0071, 0x065F00B2, 0x066000A7, 0x06620078, - 0x066308A7, 0x06640078, 0x066508A7, 0x06660083, 0x06670078, 0x066A00A7, 0x066B0078, 0x06700071, - 0x06710078, 0x0673017E, 0x0674017F, 0x06750180, 0x06760181, 0x06770182, 0x06780078, 0x068100A7, - 0x06820071, 0x06860078, 0x06870071, 0x06880078, 0x06890071, 0x06940078, 0x06950071, 0x069D0078, - 0x069F00A7, 0x06A00083, 0x06A20078, 0x06A300A7, 0x06A40078, 0x06A508A7, 0x06A60083, 0x06A70078, - 0x06AB00A7, 0x06AC0078, 0x06B00071, 0x06B10078, 0x06B3017E, 0x06B4017F, 0x06B50180, 0x06B60181, - 0x06B70182, 0x06B80078, 0x06C100A7, 0x06C20071, 0x06CB0078, 0x06CD0071, 0x06DF0078, 0x06E00071, - 0x06E30078, 0x06E700A7, 0x06E90083, 0x06EA0078, 0x06EC00A7, 0x06EE08A7, 0x06EF00A7, 0x06F00078, - 0x06F900A7, 0x06FA0078, 0x07000071, 0x07180083, 0x07191071, 0x071A0083, 0x071D0078, 0x071F0008, - 0x07200071, 0x07230083, 0x07270097, 0x0728017E, 0x0729017F, 0x072A0180, 0x072B0181, 0x072C0182, - 0x072D0097, 0x072E0078, 0x07400071, 0x07410078, 0x07430071, 0x07440078, 0x07460071, 0x07470078, - 0x074A0071, 0x07540078, 0x07550071, 0x07580083, 0x07591071, 0x075A0083, 0x075E0071, 0x075F0078, - 0x07600071, 0x07620078, 0x07640083, 0x07670078, 0x0768017E, 0x0769017F, 0x076A0180, 0x076B0181, - 0x076C0182, 0x076D0078, 0x076E1071, 0x076F0078, 0x07800094, 0x07820097, 0x07890094, 0x078C0083, - 0x078D0094, 0x0790017E, 0x0791017F, 0x07920180, 0x07930181, 0x07940182, 0x079500B3, 0x079A0083, - 0x079D00BF, 0x079F00A7, 0x07A00071, 0x07A10871, 0x07A20071, 0x07A60871, 0x07A70071, 0x07AB0871, - 0x07AC0071, 0x07B40871, 0x07B50078, 0x07B80083, 0x07B90883, 0x07BB1083, 0x07BD0083, 0x07BF00A7, - 0x07C00883, 0x07C10083, 0x07C20097, 0x07C30083, 0x07C40071, 0x07C60078, 0x07C80083, 0x07C90883, - 0x07CA0083, 0x07CE0883, 0x07CF0083, 0x07D30883, 0x07D40083, 0x07DC0883, 0x07DD0083, 0x07DE0078, - 0x07DF0094, 0x07E60078, 0x07E70094, 0x07E80097, 0x07E90078, 0x08000071, 0x08150078, 0x08160083, - 0x081800A7, 0x08190078, 0x081B0083, 0x081D0078, 0x0820017E, 0x0821017F, 0x08220180, 0x08230181, - 0x08240182, 0x08250097, 0x08280071, 0x082B00A7, 0x082C0083, 0x082D0078, 0x085000B5, 0x08630078, - 0x08680071, 0x087D0097, 0x087E0078, 0x08800071, 0x08AD0078, 0x08AF0071, 0x08D10078, 0x08D40071, - 0x08FD0078, 0x09000071, 0x09240078, 0x09250071, 0x09270078, 0x09280071, 0x092B0078, 0x092D0071, - 0x092F0078, 0x09300071, 0x09440078, 0x09450071, 0x09470078, 0x09480071, 0x09580078, 0x09590071, - 0x095B0078, 0x095C0071, 0x095F0078, 0x09610071, 0x09630078, 0x09640071, 0x096B0078, 0x096C0071, - 0x09880078, 0x09890071, 0x098B0078, 0x098C0071, 0x09AD0078, 0x09AF0083, 0x09B00097, 0x09B400AD, - 0x09B500AE, 0x09B6012D, 0x09B7012E, 0x09B8012F, 0x09B90185, 0x09BA0186, 0x09BB0187, 0x09BC0188, - 0x09BD0184, 0x09BE0078, 0x09C00071, 0x09C80054, 0x09CD0078, 0x09D00071, 0x09FA0078, 0x0A000071, - 0x0B360097, 0x0B370071, 0x0B3B0078, 0x0B400071, 0x0B4D00B4, 0x0B4E0078, 0x0B500071, 0x0B750097, - 0x0B770189, 0x0B780078, 0x0B800071, 0x0B860078, 0x0B870071, 0x0B890083, 0x0B8A0078, 0x0B900071, - 0x0B990083, 0x0B9A0097, 0x0B9B0078, 0x0BA00071, 0x0BA90083, 0x0BAA0078, 0x0BB00071, 0x0BB60078, - 0x0BB70071, 0x0BB80078, 0x0BB90083, 0x0BBA0078, 0x0BC00071, 0x0BDA00C2, 0x0BDB0083, 0x0BDF00A7, - 0x0BE40083, 0x0BEA0097, 0x0BEB0081, 0x0BEC0097, 0x0BED0008, 0x0BEE0083, 0x0BEF0078, 0x0BF0017E, - 0x0BF1017F, 0x0BF20180, 0x0BF30181, 0x0BF40182, 0x0BF50078, 0x0BF80106, 0x0BF90107, 0x0BFA0108, - 0x0BFB0109, 0x0BFC010A, 0x0BFD0078, 0x0C000006, 0x0C050083, 0x0C070078, 0x0C08017E, 0x0C09017F, - 0x0C0A0180, 0x0C0B0181, 0x0C0C0182, 0x0C0D0078, 0x0C100071, 0x0C210081, 0x0C220071, 0x0C3C0078, - 0x0C400071, 0x0C540083, 0x0C550078, 0x0C800071, 0x0C8E0078, 0x0C900083, 0x0C9100A7, 0x0C930083, - 0x0C9400C8, 0x0C960078, 0x0C9800A7, 0x0C9C0083, 0x0C9E0078, 0x0CA20006, 0x0CA3017E, 0x0CA4017F, - 0x0CA50180, 0x0CA60181, 0x0CA70182, 0x0CA80071, 0x0CB70078, 0x0CB80071, 0x0CBA0078, 0x0CC00071, - 0x0CD50078, 0x0CD800A7, 0x0CE00071, 0x0CE400A7, 0x0CE50078, 0x0CE8017E, 0x0CE9017F, 0x0CEA0180, - 0x0CEB0181, 0x0CEC0182, 0x0CED0078, 0x0CEF0006, 0x0CF00054, 0x0D000071, 0x0D0B0083, 0x0D0C00A7, - 0x0D0E0078, 0x0D0F0097, 0x0D100078, 0x0E800055, 0x0E967881, 0x0E970081, 0x0E987881, 0x0E9D0081, - 0x0E9E7881, 0x0EB17055, 0x0EB50055, 0x0ECD7881, 0x0EE00083, 0x0EE20078, 0x0F000865, 0x0F4B0855, - 0x0F4D098A, 0x0F4E0078, 0x0F500865, 0x0F7D0078, 0x0F8008C9, 0x0F8408CA, 0x0F8808C9, 0x0F8B0078, - 0x0F8C08CA, 0x0F8F0078, 0x0F9008C9, 0x0F9408CA, 0x0F9808C9, 0x0F9C08CA, 0x0FA008C9, 0x0FA30078, - 0x0FA408CA, 0x0FA70078, 0x0FA808C9, 0x0FAC08CA, 0x0FB008C9, 0x0FB408CA, 0x0FB808CB, 0x0FB908CC, - 0x0FBB08CD, 0x0FBC08CE, 0x0FBD08CF, 0x0FBE08D0, 0x0FBF0078, 0x0FC008C9, 0x0FC408D1, 0x0FC808C9, - 0x0FCC08D1, 0x0FD008C9, 0x0FD408D1, 0x0FD808C9, 0x0FD9098B, 0x0FDA0078, 0x0FDB0855, 0x0FDC08CA, - 0x0FDD08D2, 0x0FDE1037, 0x0FE00837, 0x0FE1098B, 0x0FE20078, 0x0FE30855, 0x0FE408D5, 0x0FE60837, - 0x0FE808C9, 0x0FE90855, 0x0FEA0078, 0x0FEB0855, 0x0FEC08CA, 0x0FED08D6, 0x0FEE0837, 0x0FF008C9, - 0x0FF10855, 0x0FF20890, 0x0FF30855, 0x0FF408CA, 0x0FF508D7, 0x0FF60837, 0x0FF80078, 0x0FF9098B, - 0x0FFA0078, 0x0FFB0855, 0x0FFC08D9, 0x0FFD08DA, 0x0FFE0837, 0x0FFF0078, 0x10000805, 0x10011005, - 0x10035805, 0x10041005, 0x10050057, 0x1007018C, 0x10085899, 0x10090099, 0x100B1006, 0x100C018D, - 0x100D00DB, 0x100E018D, 0x100F00DB, 0x10100006, 0x10121006, 0x10130006, 0x1014018E, 0x1015018F, - 0x10160190, 0x10175853, 0x10180007, 0x10191007, 0x101A0006, 0x101B1006, 0x101C0126, 0x101D0006, - 0x101F0038, 0x10200006, 0x10220009, 0x10231006, 0x10250006, 0x102B1006, 0x102C0006, 0x102F1005, - 0x10300057, 0x10320078, 0x10350057, 0x10387855, 0x10390078, 0x103A7910, 0x103B7911, 0x103C7912, - 0x103D780B, 0x103E7809, 0x103F7855, 0x1040705D, 0x1041705B, 0x10427110, 0x10437111, 0x10447112, - 0x1045700B, 0x10467009, 0x10470078, 0x10487081, 0x104A0078, 0x10500008, 0x105B0078, 0x10680083, - 0x106E0095, 0x10700083, 0x10710095, 0x10720083, 0x10760078, 0x10801054, 0x10831077, 0x10841054, - 0x10852877, 0x10872855, 0x10882877, 0x10892855, 0x108A2877, 0x108B0054, 0x108C2877, 0x108F0054, - 0x10901054, 0x10910054, 0x10950991, 0x10962877, 0x10972855, 0x10982877, 0x109A1071, 0x109C2855, - 0x109D1054, 0x109E2855, 0x109F2877, 0x10A00019, 0x10A22877, 0x10A32855, 0x10A50019, 0x10A60078, - 0x10A9305F, 0x10AF3106, 0x10B01192, 0x10B11193, 0x10B21194, 0x10B31195, 0x10B41196, 0x10B51197, - 0x10B61198, 0x10B71199, 0x10B8119A, 0x10B9119B, 0x10BA119C, 0x10BB119D, 0x10BC119E, 0x10BD119F, - 0x10BE11A0, 0x10BF11A1, 0x10C001A2, 0x10C101A3, 0x10C20078, 0x10C80019, 0x10CA0054, 0x10CD0819, - 0x10CE0054, 0x10D10019, 0x10D20054, 0x10E60854, 0x10E70819, 0x10E80054, 0x10FA0019, 0x110000E8, - 0x11020019, 0x110408FB, 0x110500FC, 0x11070019, 0x110800E8, 0x11090059, 0x110A01A4, 0x110B0019, - 0x110D00E8, 0x11110019, 0x111500E8, 0x111610E8, 0x111800E8, 0x111A0019, 0x111C00E8, 0x111E00FE, - 0x111F00E8, 0x112008E8, 0x112101A5, 0x112200E8, 0x112308E8, 0x112500E8, 0x11260019, 0x112900FE, - 0x112B0019, 0x112F00E8, 0x11300019, 0x113200FE, 0x11360819, 0x113708FE, 0x113900FE, 0x113A08FE, - 0x113B00FE, 0x113C08FE, 0x113D00FE, 0x114008FE, 0x114100FE, 0x114208FE, 0x114300FE, 0x114408FE, - 0x114500FE, 0x11460019, 0x114700FD, 0x11490019, 0x115100FE, 0x11520019, 0x115300E8, 0x115401A6, - 0x115608E8, 0x115800FE, 0x115C0019, 0x115F00E8, 0x11600019, 0x116400FD, 0x116601A7, 0x11670019, - 0x116800FE, 0x11690019, 0x116B00FE, 0x117008FE, 0x117200FE, 0x117508FE, 0x11770019, 0x117800FE, - 0x11790102, 0x117A00E8, 0x117B0103, 0x117C00E8, 0x117D0104, 0x117E0105, 0x117F00E8, 0x11800054, - 0x118400FE, 0x11860054, 0x119000E8, 0x11910054, 0x11940809, 0x11950054, 0x119B0094, 0x11BD0054, - 0x11CA0094, 0x11CB0054, 0x11CD0019, 0x11DA00BF, 0x11DB0054, 0x11EE0078, 0x12000054, 0x12130078, - 0x12200054, 0x12250078, 0x123018C4, 0x123118C5, 0x123218C6, 0x123318C7, 0x1234191F, 0x1235191A, - 0x1236191B, 0x1237191C, 0x1238191D, 0x1239191E, 0x123A10C4, 0x123B10C5, 0x123C10C6, 0x123D10C7, - 0x123E111F, 0x123F111A, 0x1240111B, 0x1241111C, 0x1242111D, 0x1243111E, 0x1244105A, 0x124510E3, - 0x124610E4, 0x124710E5, 0x124811A8, 0x124911A9, 0x124A11AA, 0x124B11AB, 0x124C11AC, 0x124D11AD, - 0x124E1094, 0x125B1918, 0x12681919, 0x1275010B, 0x1276010C, 0x1277010D, 0x1278010E, 0x1279010F, - 0x127A0106, 0x127B0107, 0x127C0108, 0x127D0109, 0x127E010A, 0x127F00C3, 0x12800054, 0x12DB0019, - 0x12DC0054, 0x12E00019, 0x12E10054, 0x12FC0019, 0x13000054, 0x13370019, 0x13380054, 0x134E0078, - 0x13500054, 0x13590078, 0x13800054, 0x13820078, 0x13830054, 0x13850078, 0x13860054, 0x13A90078, - 0x13AC0054, 0x13AF0078, 0x13B00054, 0x13B4000A, 0x13BB00C4, 0x13BC00C5, 0x13BD00C6, 0x13BE00C7, - 0x13BF011F, 0x13C000C4, 0x13C100C5, 0x13C200C6, 0x13C300C7, 0x13C4011F, 0x13C500C4, 0x13C600C5, - 0x13C700C6, 0x13C800C7, 0x13C9011F, 0x13CA0078, 0x13CC0054, 0x13DF0078, 0x13E00019, 0x13E100FD, - 0x13E20009, 0x13E30078, 0x13E80019, 0x13E900E8, 0x13EA00FD, 0x13EB0019, 0x13EE00FD, 0x13EF0019, - 0x13F100FE, 0x13F3000A, 0x13F60078, 0x13F80019, 0x14000094, 0x14800019, 0x14C10009, 0x14C601AE, - 0x14C701AF, 0x14C80009, 0x14CC0019, 0x14CD00E8, 0x14D80019, 0x14E000FE, 0x14E100E8, 0x14E200FE, - 0x14E30019, 0x14E400E8, 0x14E50019, 0x14E700FD, 0x14E90019, 0x14EA00FE, 0x14EB0019, 0x14EC000A, - 0x14EE0019, 0x14F000E8, 0x14F30019, 0x14F400E8, 0x14F50019, 0x14FA01B0, 0x14FB00E8, 0x14FC00FE, - 0x14FD0019, 0x14FE000A, 0x14FF0019, 0x150500E8, 0x150E0019, 0x150F00E8, 0x15110019, 0x151400E8, - 0x151500FD, 0x15170019, 0x151A00FE, 0x151B0019, 0x151E00FE, 0x151F0019, 0x152B00E8, 0x152C0019, - 0x153200FE, 0x15330019, 0x153500E8, 0x15380019, 0x153900E8, 0x153A1019, 0x153B0019, 0x153C00FD, - 0x153D00E8, 0x153E00FD, 0x154200E8, 0x154500FD, 0x154600E8, 0x154800FD, 0x154E00E8, 0x155000FD, - 0x155100E8, 0x15520019, 0x155300FE, 0x155700FD, 0x155800E8, 0x155900FD, 0x155A00E8, 0x155D00FD, - 0x156300E8, 0x156600FD, 0x156B0019, 0x157101B1, 0x15730019, 0x157600FE, 0x15770019, 0x157900E8, - 0x157A0019, 0x157B00FD, 0x157D00E8, 0x157F0019, 0x15800054, 0x158A0078, 0x16000096, 0x16170078, - 0x16180098, 0x162F0078, 0x16400065, 0x16720054, 0x16750078, 0x167C0006, 0x167E005F, 0x167F0006, - 0x16800125, 0x16930078, 0x16980071, 0x16B30078, 0x16B77881, 0x16B80078, 0x16C00071, 0x16CB0078, - 0x16D00071, 0x16D30078, 0x16D40071, 0x16D70078, 0x16D80071, 0x16DB0078, 0x16DC0071, 0x16DF0078, - 0x16E00071, 0x16E30078, 0x16E40071, 0x16E70078, 0x16E80071, 0x16EB0078, 0x16EC0071, 0x16EF0078, - 0x17000006, 0x170100E0, 0x17030006, 0x17040126, 0x17050006, 0x170600E0, 0x17070006, 0x170B0099, - 0x170C0078, 0x170E00E0, 0x170F0078, 0x17400054, 0x174F1054, 0x17500054, 0x17791054, 0x177A0078, - 0x17801054, 0x17EB0078, 0x17F80054, 0x17FE0078, 0x18000006, 0x18020081, 0x180301B2, 0x1804000A, - 0x18090054, 0x180A000A, 0x180E00B4, 0x180F00BF, 0x181001B3, 0x181101B4, 0x181201B5, 0x181301B6, - 0x181401B7, 0x18150083, 0x18180081, 0x181B0054, 0x181C11B8, 0x181D0081, 0x181E0006, 0x181F0054, - 0x18200071, 0x18320871, 0x18350071, 0x18380871, 0x183A0071, 0x183B0871, 0x183D0071, 0x183E0871, - 0x183F0071, 0x184B0078, 0x184C0083, 0x184D1037, 0x184E0081, 0x184F8071, 0x18500071, 0x18620871, - 0x18650071, 0x18680871, 0x186A0071, 0x186B0871, 0x186D0071, 0x186E0871, 0x186F0071, 0x187B0871, - 0x187D0006, 0x187E0081, 0x187F8071, 0x18800078, 0x18820071, 0x18960078, 0x18981071, 0x18C70078, - 0x18C80094, 0x18C978B6, 0x18CA78B7, 0x18CB7894, 0x18D00071, 0x18DC0078, 0x18E00054, 0x18E80078, - 0x18F80071, 0x19001094, 0x190E1054, 0x190F0078, 0x191010B6, 0x191110B7, 0x191210B8, 0x191310B9, - 0x191410B0, 0x19151094, 0x19220078, 0x192819B9, 0x192919BA, 0x192A19BB, 0x192B19BC, 0x192C19BD, - 0x192D19BE, 0x192E19BF, 0x192F19C0, 0x19301894, 0x193E1854, 0x193F0094, 0x194018B6, 0x194118B7, - 0x194218B8, 0x194318B9, 0x194418B0, 0x19451894, 0x195819C1, 0x195919C2, 0x195A19C3, 0x195B19C4, - 0x195C19C5, 0x195D19C6, 0x195E19C7, 0x195F19C8, 0x19601094, 0x19666854, 0x19681894, 0x197F0078, - 0x19806894, 0x19AC1094, 0x19B86894, 0x19BB6854, 0x19BD6894, 0x19EF6854, 0x19F01094, 0x19FF6854, - 0x1A000071, 0x26DB0078, 0x26E00054, 0x27000071, 0x4FDE0078, 0x50000071, 0x500A0081, 0x500B0071, - 0x52460078, 0x52480054, 0x52630078, 0x53800037, 0x538B0078, 0x54000071, 0x54050083, 0x54060071, - 0x541100A7, 0x54120083, 0x541300A7, 0x54140054, 0x54160078, 0x56000071, 0x6BD20078, 0x6C00013E, - 0x7000013F, 0x7C800871, 0x7D070071, 0x7D0A0871, 0x7D0F0071, 0x7D120871, 0x7D130071, 0x7D150871, - 0x7D170078, 0x7D180871, 0x7D350078, 0x7D380871, 0x7D6D0078, 0x7D801055, 0x7D830078, 0x7D891055, - 0x7D8C0078, 0x7D8E089B, 0x7D90289B, 0x7D94280B, 0x7D95089B, 0x7D9B0078, 0x7D9C089B, 0x7D9E0078, - 0x7DA0089B, 0x7DA20078, 0x7DA3089B, 0x7DA7109B, 0x7DA8209E, 0x7DAA489E, 0x7DAB209E, 0x7DAC489E, - 0x7DAD209E, 0x7DAE489E, 0x7DAF209E, 0x7DB0489E, 0x7DB1209E, 0x7DB2489E, 0x7DB3209E, 0x7DB4489E, - 0x7DB5209E, 0x7DB6489E, 0x7DB7209E, 0x7DB8489E, 0x7DB9209E, 0x7DBA489E, 0x7DBB209E, 0x7DBC489E, - 0x7DBD209E, 0x7DBE489E, 0x7DBF209E, 0x7DC0489E, 0x7DC1209E, 0x7DC8489E, 0x7DC9209E, 0x7DCA489E, - 0x7DCB209E, 0x7DCC489E, 0x7DCD209E, 0x7DCE489E, 0x7DCF209E, 0x7DD1489E, 0x7DD2209E, 0x7DD4489E, - 0x7DD5209E, 0x7DD6489E, 0x7DD7209E, 0x7DD90078, 0x7DE9409E, 0x7DEA389E, 0x7DEB409E, 0x7DEF209E, - 0x7DF3489E, 0x7DF5209E, 0x7DFC409E, 0x7DFD389E, 0x7DFE209E, 0x7DFF489E, 0x7E00409E, 0x7E32209E, - 0x7E4B389E, 0x7E6F489E, 0x7E7A409E, 0x7E88209E, 0x7E96389E, 0x7E9A489E, 0x7E9E409E, 0x7E9F00BF, - 0x7EA00078, 0x7EA8209E, 0x7EA9389E, 0x7EAD209E, 0x7EAE389E, 0x7EAF209E, 0x7EB0389E, 0x7EB3209E, - 0x7EB5389E, 0x7EB7209E, 0x7EB9389E, 0x7EBA209E, 0x7EBB389E, 0x7EBC209E, 0x7EBE389E, 0x7EBF209E, - 0x7EC1389E, 0x7EC2209E, 0x7EC4389E, 0x7EC5209E, 0x7EC6389E, 0x7EC80078, 0x7EC9389E, 0x7ECB209E, - 0x7ECE389E, 0x7ECF209E, 0x7EDA389E, 0x7EDB209E, 0x7EE1389E, 0x7EE3209E, 0x7EE40078, 0x7EF8409E, - 0x7EFE0054, 0x7EFF0078, 0x7F000083, 0x7F088006, 0x7F0B80B4, 0x7F0C8006, 0x7F0D0078, 0x7F100083, - 0x7F120078, 0x7F188099, 0x7F198038, 0x7F1A80B4, 0x7F220006, 0x7F2380B4, 0x7F241006, 0x7F261038, - 0x7F286006, 0x7F290078, 0x7F2A600C, 0x7F2B6006, 0x7F2C60B4, 0x7F2F6007, 0x7F306006, 0x7F31600D, - 0x7F326019, 0x7F330078, 0x7F346008, 0x7F356006, 0x7F360078, 0x7F38489E, 0x7F39009E, 0x7F3A0078, - 0x7F3B489E, 0x7F40409E, 0x7F45389E, 0x7F46409E, 0x7F48389E, 0x7F49409E, 0x7F4B389E, 0x7F4C409E, - 0x7F4D389E, 0x7F4E409E, 0x7F4F389E, 0x7F50409E, 0x7F51389E, 0x7F52409E, 0x7F53389E, 0x7F54409E, - 0x7F59389E, 0x7F5A409E, 0x7F5B389E, 0x7F5C409E, 0x7F5D389E, 0x7F5E409E, 0x7F5F389E, 0x7F60409E, - 0x7F61389E, 0x7F62409E, 0x7F63389E, 0x7F64409E, 0x7F65389E, 0x7F66409E, 0x7F67389E, 0x7F68409E, - 0x7F69389E, 0x7F6A409E, 0x7F6B389E, 0x7F6C409E, 0x7F6D389E, 0x7F6E409E, 0x7F6F389E, 0x7F70409E, - 0x7F71389E, 0x7F72409E, 0x7F73389E, 0x7F74409E, 0x7F75389E, 0x7F76409E, 0x7F79389E, 0x7F7A409E, - 0x7F7E0078, 0x7F7F0057, 0x7F808806, 0x7F818807, 0x7F838806, 0x7F84880A, 0x7F85880B, 0x7F86880D, - 0x7F87880C, 0x7F88880F, 0x7F898811, 0x7F8A8813, 0x7F8B8815, 0x7F8C8817, 0x7F8D8806, 0x7F8E8819, - 0x7F8F8806, 0x7F908860, 0x7F9D8835, 0x7F9E8836, 0x7F9F8838, 0x7FA08861, 0x7FAD8835, 0x7FAE8836, - 0x7FAF8809, 0x7FB05006, 0x7FB1500A, 0x7FB25006, 0x7FB35071, 0x7FCF5081, 0x7FD05071, 0x7FDF0078, - 0x7FE15071, 0x7FE40078, 0x7FE55071, 0x7FE80078, 0x7FE95071, 0x7FEC0078, 0x7FED5071, 0x7FEE0078, - 0x7FF08808, 0x7FF18837, 0x7FF28808, 0x7FF30078, 0x7FF45019, 0x7FF65054, 0x7FF70078, 0x7FFC0141, - 0x7FFE0054, 0x7FFF0078, 0x80000071, 0x80130078, 0x80140071, 0x801D0078, 0x801E0071, 0x80270078, - 0x80280071, 0x802F0078, 0x80400071, 0x807D0078, 0x80800006, 0x80810078, 0x808300AD, 0x808400AE, - 0x8085012D, 0x8086012E, 0x8087012F, 0x80880185, 0x80890186, 0x808A0187, 0x808B0188, 0x808C0184, - 0x808D01C9, 0x808E01CA, 0x808F01CB, 0x809001CC, 0x809101CD, 0x809201CE, 0x809301CF, 0x809401D0, - 0x809500BE, 0x809601D1, 0x809701D2, 0x809801D3, 0x809901D4, 0x809A0078, 0x809B0094, 0x80A0014E, - 0x80A10152, 0x80A20153, 0x80A30157, 0x80A40154, 0x80A50155, 0x80A60156, 0x80A70152, 0x80A80150, - 0x80A90153, 0x80AA01D5, 0x80AB0154, 0x80AC014F, 0x80AD0158, 0x80AF0152, 0x80B00154, 0x80B201D6, - 0x80B30150, 0x80B501D7, 0x80B60153, 0x80B80156, 0x80B90152, 0x80BA005F, 0x80BC0054, 0x80C50078, - 0x81800071, 0x818F0078, 0x8190012D, 0x819100BB, 0x81920078, 0x81980071, 0x81A50078, 0x81C00071, - 0x81CF0097, 0x81D00071, 0x81E20078, 0x81E40071, 0x81E8014F, 0x81E90154, 0x81EA0155, 0x81EB0078, - 0x8200015B, 0x8214015C, 0x82280071, 0x824F0078, 0x8250017E, 0x8251017F, 0x82520180, 0x82530181, - 0x82540182, 0x82550078, 0x8400009B, 0x84030078, 0x8405009B, 0x841C0078, 0x841F009B, 0x84200078, - 0x85000083, 0x85030078, 0x85060083, 0x8508009B, 0x851A0078, 0x851C0083, 0x851D0078, 0x851F0083, - 0x852001D8, 0x852101D9, 0x852201DA, 0x852301DB, 0x85240078, 0x8528009A, 0x852C0078, 0xE8000094, - 0xE87B0078, 0xE8800094, 0xE8930078, 0xE8950094, 0xE8AF0894, 0xE8B200A7, 0xE8B30083, 0xE8B50094, - 0xE8B600A7, 0xE8B90057, 0xE8BD0083, 0xE8C10094, 0xE8C20083, 0xE8C60094, 0xE8D50083, 0xE8D70094, - 0xE8DD0894, 0xE8E00094, 0xE8EF0078, 0xE9000054, 0xE9210083, 0xE9220054, 0xE9230078, 0xE9800054, - 0xE9AB0078, 0xEA002877, 0xEA0D2855, 0xEA1A2877, 0xEA272855, 0xEA2A0078, 0xEA2B2855, 0xEA342877, - 0xEA412855, 0xEA4E0078, 0xEA4F2877, 0xEA500078, 0xEA522877, 0xEA530078, 0xEA542877, 0xEA560078, - 0xEA572877, 0xEA5B2855, 0xEA682877, 0xEA752855, 0xEA822877, 0xEA850078, 0xEA862877, 0xEA8A0078, - 0xEA8B2877, 0xEA8E0078, 0xEA8F2855, 0xEA9C2877, 0xEA9F0078, 0xEAA02877, 0xEAA20078, 0xEAA52877, - 0xEAA80078, 0xEAA92855, 0xEAB62877, 0xEAC32855, 0xEAD02877, 0xEADD2855, 0xEAEA2877, 0xEAF72855, - 0xEB042877, 0xEB112855, 0xEB1E2877, 0xEB2B2855, 0xEB382877, 0xEB452855, 0xEB530078, 0xEB542877, - 0xEB6029DC, 0xEB612855, 0xEB6D29DC, 0xEB6E2855, 0xEB712877, 0xEB7D29DC, 0xEB7E2855, 0xEB8A29DC, - 0xEB8B2855, 0xEB8E2877, 0xEB9A29DC, 0xEB9B2855, 0xEBA729DC, 0xEBA82855, 0xEBAB2877, 0xEBB729DC, - 0xEBB82855, 0xEBC429DC, 0xEBC52855, 0xEBC82877, 0xEBD429DC, 0xEBD52855, 0xEBE129DC, 0xEBE22855, - 0xEBE50078, 0xEBE7280F, 0xEBE82811, 0xEBE92813, 0xEBEA2815, 0xEBEB2817, 0xEBEC280F, 0xEBED2811, - 0xEBEE2813, 0xEBEF2815, 0xEBF02817, 0xEBF1280F, 0xEBF22811, 0xEBF32813, 0xEBF42815, 0xEBF52817, - 0xEBF6280F, 0xEBF72811, 0xEBF82813, 0xEBF92815, 0xEBFA2817, 0xEBFB280F, 0xEBFC2811, 0xEBFD2813, - 0xEBFE2815, 0xEBFF2817, 0xEC000078 - }; - - static const uint32_t a17[] = { - 0x00000071, 0x536B0078, 0x7C000871, 0x7D0F0078 - }; - - static const uint32_t a23[] = { - 0x00000057, 0x00010078, 0x00100057, 0x00400078, 0x00800083, 0x00F80078, 0x8000013F, 0xFFFF0078 - }; - - static const uint32_t a24[] = { - 0x0000013F, 0x7FFF0078 - }; - - - // The full set of all arrays to be searched. - static const Range FULL_DATA[] = { - {sizeof(a0)/sizeof(uint32_t), a0}, - {sizeof(a1)/sizeof(uint32_t), a1}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0}, - {sizeof(a7)/sizeof(uint32_t), a7}, - {sizeof(a8)/sizeof(uint32_t), a8}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0}, - {sizeof(a16)/sizeof(uint32_t), a16}, - {sizeof(a17)/sizeof(uint32_t), a17}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0}, - {sizeof(a23)/sizeof(uint32_t), a23}, - {sizeof(a24)/sizeof(uint32_t), a24}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0} - }; - - // Array of uppercase differences - static const short UCDIFF[] = { - 0, -32, 743, 121, -1, -232, -300, 97, - 163, 130, 56, -2, -79, -210, -206, -205, - -202, -203, -207, -209, -211, -213, -214, -218, - -217, -219, -83, 84, -38, -37, -31, -64, - -63, -62, -57, -47, -54, -86, -80, 7, - -96, -48, -59, 8, 74, 86, 100, 128, - 112, 126, 9, -7205, -16, -26, -7264, -40 - }; - - // Array of lowercase differences - static const short LCDIFF[] = { - 0, 32, 1, -199, -121, 210, 206, 205, - 79, 202, 203, 207, 211, 209, 213, 214, - 218, 217, 219, 2, -97, -56, -130, -163, - 83, 38, 37, 64, 63, -60, -7, 80, - 48, 7264, -8, -74, -9, -86, -100, -112, - -128, -126, -7517, -8383, -8262, 16, 26, 40 - }; - - // Array of titlecase differences - static const short TCDIFF[] = { - 3, 1, 0, -1 - }; - - // Array of mirrored character differences - static const short MIRROR_DIFF[] = { - 0, 1, -1, 2, -2, 16, -16, 3, - -3, 2016, 138, 1824, 2104, 2108, 2106, -138, - 8, 7, -8, -7, -1824, -2016, -2104, -2106, - -2108 - }; - - // Array of all possible numeric values - static const int NUMERICS[] = { - -1, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 29, 30, - 31, 32, 33, 34, 35, -2, 100, 1000, - 40, 50, 60, 70, 80, 90, 10000, 500, - 5000, 36, 37, 38, 39, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 200, 300, - 400, 600, 700, 800, 900, 2000, 3000, 4000, - 6000, 7000, 8000, 9000, 20000, 30000, 40000, 50000, - 60000, 70000, 80000, 90000 - }; - - // All possible packed data values, no duplicates - static const uint32_t PACKED_DATA[] = { - 0x00000000, 0x0000012F, 0x0000016F, 0x0000014F, 0x0000018F, 0x0000018C, 0x000001B8, 0x000000B8, - 0x000000BA, 0x020005B5, 0x040005B6, 0x00000099, 0x000000F8, 0x00000094, 0x02000069, 0x04000069, - 0x06000069, 0x08000069, 0x0A000069, 0x0C000069, 0x0E000069, 0x10000069, 0x12000069, 0x14000069, - 0x060005B9, 0x000001B9, 0x080005B9, 0x16020001, 0x18020001, 0x1A020001, 0x1C020001, 0x1E020001, - 0x20020001, 0x22020001, 0x24020001, 0x26020001, 0x28020001, 0x2A020001, 0x2C020001, 0x2E020001, - 0x30020001, 0x32020001, 0x34020001, 0x36020001, 0x38020001, 0x3A020001, 0x3C020001, 0x3E020001, - 0x40020001, 0x42020001, 0x44020001, 0x46020001, 0x48020001, 0x060005B5, 0x080005B6, 0x000001BB, - 0x000001B7, 0x16000802, 0x18000802, 0x1A000802, 0x1C000802, 0x1E000802, 0x20000802, 0x22000802, - 0x24000802, 0x26000802, 0x28000802, 0x2A000802, 0x2C000802, 0x2E000802, 0x30000802, 0x32000802, - 0x34000802, 0x36000802, 0x38000802, 0x3A000802, 0x3C000802, 0x3E000802, 0x40000802, 0x42000802, - 0x44000802, 0x46000802, 0x48000802, 0x000000EC, 0x000001BC, 0x00000002, 0x0A0005BD, 0x00000130, - 0x000000BC, 0x000000B9, 0x0600006B, 0x0800006B, 0x00001002, 0x0400006B, 0x0C0005BE, 0x4A0001AB, - 0x00020001, 0x00000802, 0x00001802, 0x00040001, 0x00060001, 0x00002002, 0x00080001, 0x000C0001, - 0x000E0001, 0x00100001, 0x00140001, 0x00160001, 0x00180001, 0x00004002, 0x00004802, 0x00200001, - 0x00220001, 0x00000005, 0x00A60001, 0x01805802, 0x01042003, 0x00280001, 0x002C0001, 0x00000001, - 0x00000000, 0x00007002, 0x00007802, 0x00009802, 0x0000A802, 0x0000B802, 0x0000C002, 0x0000C802, - 0x0000D002, 0x00000004, 0x000001A4, 0x00000106, 0x00320001, 0x00340001, 0x00360001, 0x00380001, - 0x0000E002, 0x0000E802, 0x0000F002, 0x0000F802, 0x00010002, 0x00010802, 0x00012002, 0x00012802, - 0x00013802, 0x003A0001, 0x003E0001, 0x00013002, 0x0000001C, 0x00000107, 0x00400001, 0x00000018, - 0x00014802, 0x000001B4, 0x00000038, 0x00000025, 0x00000050, 0x00000058, 0x00000045, 0x00000044, - 0x020000C9, 0x060000C9, 0x0A0000C9, 0x0E0000C9, 0x120000C9, 0x000000D8, 0x0000005C, 0x00000008, - 0x02000009, 0x06000009, 0x0A000009, 0x0E000009, 0x12000009, 0x0400000B, 0x0800000B, 0x0000000B, - 0x1600000B, 0x4E00000B, 0x00000006, 0x4A00000B, 0x000001B5, 0x00420001, 0x0600000B, 0x0A00000B, - 0x0E00000B, 0x1200000B, 0x3E00000B, 0x5200000B, 0x5600000B, 0x5A00000B, 0x5C00000B, 0x000001B6, - 0x2400000A, 0x2800000A, 0x00000010, 0x020001AB, 0x060001AB, 0x0A0001AB, 0x0E0001AB, 0x120001AB, - 0x00000108, 0x00015802, 0x00440001, 0x00016002, 0x00016802, 0x00017002, 0x00017802, 0x00018002, - 0x00018802, 0x00440003, 0x00460001, 0x00480003, 0x00019802, 0x004A0001, 0x004C0001, 0x004E0001, - 0x003C0001, 0x00500001, 0x00520001, 0x000001BD, 0x0000018D, 0x000001D0, 0x00000250, 0x00000230, - 0x040005BE, 0x000000F9, 0x0200006B, 0x0A00006B, 0x0E00006B, 0x1200006B, 0x00540001, 0x00560001, - 0x000005B9, 0x045A000A, 0x085A000A, 0x0C5A000A, 0x105A000A, 0x145A000A, 0x185A000A, 0x525A000A, - 0x5E5A000A, 0x0401A00A, 0x0801A00A, 0x0C01A00A, 0x1001A00A, 0x1401A00A, 0x1801A00A, 0x5201A00A, - 0x5E01A00A, 0x4E00000A, 0x5C00000A, 0x0E0005B9, 0x100005B9, 0x020005B9, 0x040005B9, 0x160005B9, - 0x180005B9, 0x1A0005B9, 0x200005B9, 0x220005B9, 0x240005B9, 0x260005B9, 0x040001AB, 0x080001AB, - 0x0C0001AB, 0x100001AB, 0x140001AB, 0x180001AB, 0x1C0001AB, 0x200001AB, 0x240001AB, 0x280001AB, - 0x0C00006B, 0x1000006B, 0x1400006B, 0x1800006B, 0x1C00006B, 0x2000006B, 0x2400006B, 0x2800006B, - 0x005C001C, 0x0001A81C, 0x1A0001AB, 0x1E0001AB, 0x220001AB, 0x260001AB, 0x2A0001AB, 0x160001AB, - 0x020005B6, 0x100005B6, 0x280005B9, 0x2C0005B9, 0x300005B9, 0x0001B002, 0x020005BD, 0x0600000A, - 0x0A00000A, 0x0E00000A, 0x1200000A, 0x1600000A, 0x3E00000A, 0x0C00000B, 0x1000000B, 0x1400000B, - 0x2E0001AB, 0x320001AB, 0x360001AB, 0x3A0001AB, 0x3E0001AB, 0x420001AB, 0x460001AB, 0x640001AB, - 0x680001AB, 0x6A0001AB, 0x6E0001AB, 0x720001AB, 0x760001AB, 0x7A0001AB, 0x00000013, 0x00000012, - 0x0000005A, 0x000001B0, 0x7C00000B, 0x8000000B, 0x8200000B, 0x8600000B, 0x8C00000B, 0x6000000B, - 0x9200000B, 0x9600000B, 0x9800000B, 0x9C00000B, 0xA000000B, 0xA400000B, 0x4A0001AA, 0x040001AA, - 0x520001AA, 0x600001AA, 0x0C0001AA, 0x5E0001AA, 0x160001AA, 0x4C0001AA, 0x4E0001AA, 0x9E0001AA, - 0x060001AA, 0x8800000A, 0x2A0001AA, 0x005E0001, 0x0001B802, 0x0400002B, 0x0800002B, 0x1600002B, - 0x4C00002B, 0x00002802, 0x00003002, 0x000A0001, 0x00120001, 0x00003802, 0x001A0001, 0x001C0001, - 0x001E0001, 0x00240001, 0x00005002, 0x00006002, 0x002A0001, 0x002E0001, 0x00300001, 0x00006802, - 0x00008002, 0x00008802, 0x00009002, 0x0000A002, 0x0000B002, 0x0000D906, 0x00011002, 0x00011802, - 0x00014002, 0x040000C9, 0x080000C9, 0x0C0000C9, 0x100000C9, 0x140000C9, 0x04000009, 0x08000009, - 0x0C000009, 0x10000009, 0x14000009, 0x2200000B, 0x4C00000B, 0x2A00000B, 0x5000000B, 0x5400000B, - 0x5800000B, 0x2600000A, 0x00015002, 0x00019002, 0x00000030, 0x000001BE, 0x0000014E, 0x00000210, - 0x000001F0, 0x00580001, 0x065A000A, 0x0A5A000A, 0x0E5A000A, 0x125A000A, 0x165A000A, 0x1A5A000A, - 0x4C5A000A, 0x4E5A000A, 0x0601A00A, 0x0A01A00A, 0x0E01A00A, 0x1201A00A, 0x1601A00A, 0x1A01A00A, - 0x4C01A00A, 0x4E01A00A, 0x6000000A, 0x0000000A, 0x120005B9, 0x140005B9, 0x1C0005B9, 0x1E0005B9, - 0x1600006B, 0x1A00006B, 0x1E00006B, 0x2200006B, 0x2600006B, 0x2A00006B, 0x0E0005B5, 0x040005B5, - 0x2A0005B9, 0x2E0005B9, 0x0200000A, 0x0400000A, 0x0800000A, 0x0C00000A, 0x1000000A, 0x1400000A, - 0x2A00000A, 0x2C0001AB, 0x300001AB, 0x340001AB, 0x380001AB, 0x3C0001AB, 0x400001AB, 0x440001AB, - 0x480001AB, 0x620001AB, 0x660001AB, 0x500001AB, 0x6C0001AB, 0x700001AB, 0x740001AB, 0x780001AB, - 0x520001AB, 0x7E00000B, 0x5E00000B, 0x8400000B, 0x8800000B, 0x8A00000B, 0x8E00000B, 0x9000000B, - 0x9400000B, 0x9A00000B, 0x9E00000B, 0xA200000B, 0xA600000B, 0x5C0001AA, 0x3E0001AA, 0x7E0001AA, - 0x0600002B, 0x0A00002B, 0x2A00002B, 0x4E00002B, 0x00000019 - }; -} diff --git a/libs/utils/Flattenable.cpp b/libs/utils/Flattenable.cpp new file mode 100644 index 0000000..1f2ffaa --- /dev/null +++ b/libs/utils/Flattenable.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2006 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/Flattenable.h> + +namespace android { + +Flattenable::~Flattenable() { +} + +}; // namespace android diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp index 450af8d..7e0f881 100644 --- a/libs/utils/ResourceTypes.cpp +++ b/libs/utils/ResourceTypes.cpp @@ -229,12 +229,12 @@ Res_png_9patch* Res_png_9patch::deserialize(const void* inData) // -------------------------------------------------------------------- ResStringPool::ResStringPool() - : mError(NO_INIT), mOwnedData(NULL) + : mError(NO_INIT), mOwnedData(NULL), mHeader(NULL), mCache(NULL) { } ResStringPool::ResStringPool(const void* data, size_t size, bool copyData) - : mError(NO_INIT), mOwnedData(NULL) + : mError(NO_INIT), mOwnedData(NULL), mHeader(NULL), mCache(NULL) { setTo(data, size, copyData); } @@ -296,7 +296,17 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData) (int)size); return (mError=BAD_TYPE); } - mStrings = (const char16_t*) + + size_t charSize; + if (mHeader->flags&ResStringPool_header::UTF8_FLAG) { + charSize = sizeof(uint8_t); + mCache = (char16_t**)malloc(sizeof(char16_t**)*mHeader->stringCount); + memset(mCache, 0, sizeof(char16_t**)*mHeader->stringCount); + } else { + charSize = sizeof(char16_t); + } + + mStrings = (const void*) (((const uint8_t*)data)+mHeader->stringsStart); if (mHeader->stringsStart >= (mHeader->header.size-sizeof(uint16_t))) { LOGW("Bad string block: string pool starts at %d, after total size %d\n", @@ -305,7 +315,7 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData) } if (mHeader->styleCount == 0) { mStringPoolSize = - (mHeader->header.size-mHeader->stringsStart)/sizeof(uint16_t); + (mHeader->header.size-mHeader->stringsStart)/charSize; } else { // check invariant: styles follow the strings if (mHeader->stylesStart <= mHeader->stringsStart) { @@ -314,7 +324,7 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData) return (mError=BAD_TYPE); } mStringPoolSize = - (mHeader->stylesStart-mHeader->stringsStart)/sizeof(uint16_t); + (mHeader->stylesStart-mHeader->stringsStart)/charSize; } // check invariant: stringCount > 0 requires a string pool to exist @@ -329,13 +339,19 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData) for (i=0; i<mHeader->stringCount; i++) { e[i] = dtohl(mEntries[i]); } - char16_t* s = const_cast<char16_t*>(mStrings); - for (i=0; i<mStringPoolSize; i++) { - s[i] = dtohs(mStrings[i]); + if (!(mHeader->flags&ResStringPool_header::UTF8_FLAG)) { + const char16_t* strings = (const char16_t*)mStrings; + char16_t* s = const_cast<char16_t*>(strings); + for (i=0; i<mStringPoolSize; i++) { + s[i] = dtohs(strings[i]); + } } } - if (mStrings[mStringPoolSize-1] != 0) { + if ((mHeader->flags&ResStringPool_header::UTF8_FLAG && + ((uint8_t*)mStrings)[mStringPoolSize-1] != 0) || + (!mHeader->flags&ResStringPool_header::UTF8_FLAG && + ((char16_t*)mStrings)[mStringPoolSize-1] != 0)) { LOGW("Bad string block: last string is not 0-terminated\n"); return (mError=BAD_TYPE); } @@ -410,24 +426,95 @@ void ResStringPool::uninit() free(mOwnedData); mOwnedData = NULL; } + if (mHeader != NULL && mCache != NULL) { + for (size_t x = 0; x < mHeader->stringCount; x++) { + if (mCache[x] != NULL) { + free(mCache[x]); + mCache[x] = NULL; + } + } + free(mCache); + mCache = NULL; + } } +#define DECODE_LENGTH(str, chrsz, len) \ + len = *(str); \ + if (*(str)&(1<<(chrsz*8-1))) { \ + (str)++; \ + len = (((len)&((1<<(chrsz*8-1))-1))<<(chrsz*8)) + *(str); \ + } \ + (str)++; + const uint16_t* ResStringPool::stringAt(size_t idx, size_t* outLen) const { if (mError == NO_ERROR && idx < mHeader->stringCount) { - const uint32_t off = (mEntries[idx]/sizeof(uint16_t)); + const bool isUTF8 = (mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0; + const uint32_t off = mEntries[idx]/(isUTF8?sizeof(char):sizeof(char16_t)); if (off < (mStringPoolSize-1)) { - const char16_t* str = mStrings+off; - *outLen = *str; - if ((*str)&0x8000) { - str++; - *outLen = (((*outLen)&0x7fff)<<16) + *str; - } - if ((uint32_t)(str+1+*outLen-mStrings) < mStringPoolSize) { - return str+1; + if (!isUTF8) { + const char16_t* strings = (char16_t*)mStrings; + const char16_t* str = strings+off; + DECODE_LENGTH(str, sizeof(char16_t), *outLen) + if ((uint32_t)(str+*outLen-strings) < mStringPoolSize) { + return str; + } else { + LOGW("Bad string block: string #%d extends to %d, past end at %d\n", + (int)idx, (int)(str+*outLen-strings), (int)mStringPoolSize); + } } else { - LOGW("Bad string block: string #%d extends to %d, past end at %d\n", - (int)idx, (int)(str+1+*outLen-mStrings), (int)mStringPoolSize); + const uint8_t* strings = (uint8_t*)mStrings; + const uint8_t* str = strings+off; + DECODE_LENGTH(str, sizeof(uint8_t), *outLen) + size_t encLen; + DECODE_LENGTH(str, sizeof(uint8_t), encLen) + if ((uint32_t)(str+encLen-strings) < mStringPoolSize) { + AutoMutex lock(mDecodeLock); + if (mCache[idx] != NULL) { + return mCache[idx]; + } + char16_t *u16str = (char16_t *)calloc(*outLen+1, sizeof(char16_t)); + if (!u16str) { + LOGW("No memory when trying to allocate decode cache for string #%d\n", + (int)idx); + return NULL; + } + const unsigned char *u8src = reinterpret_cast<const unsigned char *>(str); + utf8_to_utf16(u8src, encLen, u16str, *outLen); + mCache[idx] = u16str; + return u16str; + } else { + LOGW("Bad string block: string #%d extends to %d, past end at %d\n", + (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize); + } + } + } else { + LOGW("Bad string block: string #%d entry is at %d, past end at %d\n", + (int)idx, (int)(off*sizeof(uint16_t)), + (int)(mStringPoolSize*sizeof(uint16_t))); + } + } + return NULL; +} + +const char* ResStringPool::string8At(size_t idx, size_t* outLen) const +{ + if (mError == NO_ERROR && idx < mHeader->stringCount) { + const bool isUTF8 = (mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0; + const uint32_t off = mEntries[idx]/(isUTF8?sizeof(char):sizeof(char16_t)); + if (off < (mStringPoolSize-1)) { + if (isUTF8) { + const uint8_t* strings = (uint8_t*)mStrings; + const uint8_t* str = strings+off; + DECODE_LENGTH(str, sizeof(uint8_t), *outLen) + size_t encLen; + DECODE_LENGTH(str, sizeof(uint8_t), encLen) + if ((uint32_t)(str+encLen-strings) < mStringPoolSize) { + return (const char*)str; + } else { + LOGW("Bad string block: string #%d extends to %d, past end at %d\n", + (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize); + } } } else { LOGW("Bad string block: string #%d entry is at %d, past end at %d\n", @@ -466,6 +553,10 @@ ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const size_t len; + // TODO optimize searching for UTF-8 strings taking into account + // the cache fill to determine when to convert the searched-for + // string key to UTF-8. + if (mHeader->flags&ResStringPool_header::SORTED_FLAG) { // Do a binary search for the string... ssize_t l = 0; @@ -513,6 +604,13 @@ size_t ResStringPool::size() const return (mError == NO_ERROR) ? mHeader->stringCount : 0; } +#ifndef HAVE_ANDROID_OS +bool ResStringPool::isUTF8() const +{ + return (mHeader->flags&ResStringPool_header::UTF8_FLAG)!=0; +} +#endif + // -------------------------------------------------------------------- // -------------------------------------------------------------------- // -------------------------------------------------------------------- @@ -527,6 +625,10 @@ void ResXMLParser::restart() mCurNode = NULL; mEventCode = mTree.mError == NO_ERROR ? START_DOCUMENT : BAD_DOCUMENT; } +const ResStringPool& ResXMLParser::getStrings() const +{ + return mTree.mStrings; +} ResXMLParser::event_code_t ResXMLParser::getEventType() const { @@ -1043,6 +1145,7 @@ status_t ResXMLTree::getError() const void ResXMLTree::uninit() { mError = NO_INIT; + mStrings.uninit(); if (mOwnedData) { free(mOwnedData); mOwnedData = NULL; @@ -1050,11 +1153,6 @@ void ResXMLTree::uninit() restart(); } -const ResStringPool& ResXMLTree::getStrings() const -{ - return mStrings; -} - status_t ResXMLTree::validateNode(const ResXMLTree_node* node) const { const uint16_t eventCode = dtohs(node->header.type); @@ -1751,7 +1849,7 @@ bool ResTable::getResourceName(uint32_t resID, resource_name* outName) const if (Res_GETPACKAGE(resID)+1 == 0) { LOGW("No package identifier when getting name for resource number 0x%08x", resID); } else { - LOGW("Resources don't contain package for resource number 0x%08x", resID); + LOGW("No known package when getting name for resource number 0x%08x", resID); } return false; } @@ -1799,9 +1897,9 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag if (p < 0) { if (Res_GETPACKAGE(resID)+1 == 0) { - LOGW("No package identifier when getting name for resource number 0x%08x", resID); + LOGW("No package identifier when getting value for resource number 0x%08x", resID); } else { - LOGW("Resources don't contain package for resource number 0x%08x", resID); + LOGW("No known package when getting value for resource number 0x%08x", resID); } return BAD_INDEX; } @@ -1822,7 +1920,7 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag const PackageGroup* const grp = mPackageGroups[p]; if (grp == NULL) { LOGW("Bad identifier when getting value for resource number 0x%08x", resID); - return false; + return BAD_INDEX; } size_t ip = grp->packages.size(); while (ip > 0) { @@ -1904,7 +2002,7 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag return bestPackage->header->index; } - return BAD_INDEX; + return BAD_VALUE; } ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex, @@ -1919,6 +2017,9 @@ ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex, uint32_t newFlags = 0; const ssize_t newIndex = getResource(value->data, value, true, &newFlags, outConfig); + if (newIndex == BAD_INDEX) { + return BAD_INDEX; + } TABLE_THEME(LOGI("Resolving reference %p: newIndex=%d, type=0x%x, data=%p\n", (void*)lastRef, (int)newIndex, (int)value->dataType, (void*)value->data)); //printf("Getting reference 0x%08x: newIndex=%d\n", value->data, newIndex); @@ -3947,13 +4048,19 @@ void ResTable::print_value(const Package* pkg, const Res_value& value) const printf("(attribute) 0x%08x\n", value.data); } else if (value.dataType == Res_value::TYPE_STRING) { size_t len; - const char16_t* str = pkg->header->values.stringAt( + const char* str8 = pkg->header->values.string8At( value.data, &len); - if (str == NULL) { - printf("(string) null\n"); + if (str8 != NULL) { + printf("(string8) \"%s\"\n", str8); } else { - printf("(string) \"%s\"\n", - String8(str, len).string()); + const char16_t* str16 = pkg->header->values.stringAt( + value.data, &len); + if (str16 != NULL) { + printf("(string16) \"%s\"\n", + String8(str16, len).string()); + } else { + printf("(string) null\n"); + } } } else if (value.dataType == Res_value::TYPE_FLOAT) { printf("(float) %g\n", *(const float*)&value.data); @@ -4044,22 +4151,165 @@ void ResTable::print(bool inclValues) const } else { sprintf(density, "%d", (int)dval); } - printf(" config %d lang=%c%c cnt=%c%c orien=%d touch=%d density=%s key=%d infl=%d nav=%d w=%d h=%d sz=%d lng=%d\n", - (int)configIndex, - type->config.language[0] ? type->config.language[0] : '-', - type->config.language[1] ? type->config.language[1] : '-', - type->config.country[0] ? type->config.country[0] : '-', - type->config.country[1] ? type->config.country[1] : '-', - type->config.orientation, - type->config.touchscreen, - density, - type->config.keyboard, - type->config.inputFlags, - type->config.navigation, - dtohs(type->config.screenWidth), - dtohs(type->config.screenHeight), - type->config.screenLayout&ResTable_config::MASK_SCREENSIZE, - type->config.screenLayout&ResTable_config::MASK_SCREENLONG); + printf(" config %d", (int)configIndex); + if (type->config.mcc != 0) { + printf(" mcc=%d", dtohs(type->config.mcc)); + } + if (type->config.mnc != 0) { + printf(" mnc=%d", dtohs(type->config.mnc)); + } + if (type->config.locale != 0) { + printf(" lang=%c%c cnt=%c%c", + type->config.language[0] ? type->config.language[0] : '-', + type->config.language[1] ? type->config.language[1] : '-', + type->config.country[0] ? type->config.country[0] : '-', + type->config.country[1] ? type->config.country[1] : '-'); + } + if (type->config.screenLayout != 0) { + printf(" sz=%d", + type->config.screenLayout&ResTable_config::MASK_SCREENSIZE); + switch (type->config.screenLayout&ResTable_config::MASK_SCREENSIZE) { + case ResTable_config::SCREENSIZE_SMALL: + printf(" (small)"); + break; + case ResTable_config::SCREENSIZE_NORMAL: + printf(" (normal)"); + break; + case ResTable_config::SCREENSIZE_LARGE: + printf(" (large)"); + break; + } + printf(" lng=%d", + type->config.screenLayout&ResTable_config::MASK_SCREENLONG); + switch (type->config.screenLayout&ResTable_config::MASK_SCREENLONG) { + case ResTable_config::SCREENLONG_NO: + printf(" (notlong)"); + break; + case ResTable_config::SCREENLONG_YES: + printf(" (long)"); + break; + } + } + if (type->config.orientation != 0) { + printf(" orient=%d", type->config.orientation); + switch (type->config.orientation) { + case ResTable_config::ORIENTATION_PORT: + printf(" (port)"); + break; + case ResTable_config::ORIENTATION_LAND: + printf(" (land)"); + break; + case ResTable_config::ORIENTATION_SQUARE: + printf(" (square)"); + break; + } + } + if (type->config.uiMode != 0) { + printf(" type=%d", + type->config.uiMode&ResTable_config::MASK_UI_MODE_TYPE); + switch (type->config.uiMode&ResTable_config::MASK_UI_MODE_TYPE) { + case ResTable_config::UI_MODE_TYPE_NORMAL: + printf(" (normal)"); + break; + case ResTable_config::UI_MODE_TYPE_CAR: + printf(" (car)"); + break; + } + printf(" night=%d", + type->config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT); + switch (type->config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT) { + case ResTable_config::UI_MODE_NIGHT_NO: + printf(" (no)"); + break; + case ResTable_config::UI_MODE_NIGHT_YES: + printf(" (yes)"); + break; + } + } + if (dval != 0) { + printf(" density=%s", density); + } + if (type->config.touchscreen != 0) { + printf(" touch=%d", type->config.touchscreen); + switch (type->config.touchscreen) { + case ResTable_config::TOUCHSCREEN_NOTOUCH: + printf(" (notouch)"); + break; + case ResTable_config::TOUCHSCREEN_STYLUS: + printf(" (stylus)"); + break; + case ResTable_config::TOUCHSCREEN_FINGER: + printf(" (finger)"); + break; + } + } + if (type->config.inputFlags != 0) { + printf(" keyhid=%d", type->config.inputFlags&ResTable_config::MASK_KEYSHIDDEN); + switch (type->config.inputFlags&ResTable_config::MASK_KEYSHIDDEN) { + case ResTable_config::KEYSHIDDEN_NO: + printf(" (no)"); + break; + case ResTable_config::KEYSHIDDEN_YES: + printf(" (yes)"); + break; + case ResTable_config::KEYSHIDDEN_SOFT: + printf(" (soft)"); + break; + } + printf(" navhid=%d", type->config.inputFlags&ResTable_config::MASK_NAVHIDDEN); + switch (type->config.inputFlags&ResTable_config::MASK_NAVHIDDEN) { + case ResTable_config::NAVHIDDEN_NO: + printf(" (no)"); + break; + case ResTable_config::NAVHIDDEN_YES: + printf(" (yes)"); + break; + } + } + if (type->config.keyboard != 0) { + printf(" kbd=%d", type->config.keyboard); + switch (type->config.keyboard) { + case ResTable_config::KEYBOARD_NOKEYS: + printf(" (nokeys)"); + break; + case ResTable_config::KEYBOARD_QWERTY: + printf(" (qwerty)"); + break; + case ResTable_config::KEYBOARD_12KEY: + printf(" (12key)"); + break; + } + } + if (type->config.navigation != 0) { + printf(" nav=%d", type->config.navigation); + switch (type->config.navigation) { + case ResTable_config::NAVIGATION_NONAV: + printf(" (nonav)"); + break; + case ResTable_config::NAVIGATION_DPAD: + printf(" (dpad)"); + break; + case ResTable_config::NAVIGATION_TRACKBALL: + printf(" (trackball)"); + break; + case ResTable_config::NAVIGATION_WHEEL: + printf(" (wheel)"); + break; + } + } + if (type->config.screenWidth != 0) { + printf(" w=%d", dtohs(type->config.screenWidth)); + } + if (type->config.screenHeight != 0) { + printf(" h=%d", dtohs(type->config.screenHeight)); + } + if (type->config.sdkVersion != 0) { + printf(" sdk=%d", dtohs(type->config.sdkVersion)); + } + if (type->config.minorVersion != 0) { + printf(" mver=%d", dtohs(type->config.minorVersion)); + } + printf("\n"); size_t entryCount = dtohl(type->entryCount); uint32_t entriesStart = dtohl(type->entriesStart); if ((entriesStart&0x3) != 0) { diff --git a/libs/utils/String16.cpp b/libs/utils/String16.cpp index aef67f2..eab7b2b 100644 --- a/libs/utils/String16.cpp +++ b/libs/utils/String16.cpp @@ -172,10 +172,6 @@ int strzcmp16_h_n(const char16_t *s1H, size_t n1, const char16_t *s2N, size_t n2 : 0); } -// --------------------------------------------------------------------------- - -namespace android { - static inline size_t utf8_char_len(uint8_t ch) { @@ -215,8 +211,38 @@ utf8_to_utf32(const uint8_t *src, size_t length) //printf("Char at %p: len=%d, utf-16=%p\n", src, length, (void*)result); } +void +utf8_to_utf16(const uint8_t *src, size_t srcLen, + char16_t* dst, const size_t dstLen) +{ + const uint8_t* const end = src + srcLen; + const char16_t* const dstEnd = dst + dstLen; + while (src < end && dst < dstEnd) { + size_t len = utf8_char_len(*src); + uint32_t codepoint = utf8_to_utf32((const uint8_t*)src, len); + + // Convert the UTF32 codepoint to one or more UTF16 codepoints + if (codepoint <= 0xFFFF) { + // Single UTF16 character + *dst++ = (char16_t) codepoint; + } else { + // Multiple UTF16 characters with surrogates + codepoint = codepoint - 0x10000; + *dst++ = (char16_t) ((codepoint >> 10) + 0xD800); + *dst++ = (char16_t) ((codepoint & 0x3FF) + 0xDC00); + } + + src += len; + } + if (dst < dstEnd) { + *dst = 0; + } +} + // --------------------------------------------------------------------------- +namespace android { + static SharedBuffer* gEmptyStringBuf = NULL; static char16_t* gEmptyString = NULL; @@ -260,30 +286,14 @@ static char16_t* allocFromUTF8(const char* in, size_t len) p += utf8len; } - SharedBuffer* buf = SharedBuffer::alloc((chars+1)*sizeof(char16_t)); + size_t bufSize = (chars+1)*sizeof(char16_t); + SharedBuffer* buf = SharedBuffer::alloc(bufSize); if (buf) { p = in; char16_t* str = (char16_t*)buf->data(); - char16_t* d = str; - while (p < end) { - size_t len = utf8_char_len(*p); - uint32_t codepoint = utf8_to_utf32((const uint8_t*)p, len); - - // Convert the UTF32 codepoint to one or more UTF16 codepoints - if (codepoint <= 0xFFFF) { - // Single UTF16 character - *d++ = (char16_t) codepoint; - } else { - // Multiple UTF16 characters with surrogates - codepoint = codepoint - 0x10000; - *d++ = (char16_t) ((codepoint >> 10) + 0xD800); - *d++ = (char16_t) ((codepoint & 0x3FF) + 0xDC00); - } - - p += len; - } - *d = 0; + utf8_to_utf16((const uint8_t*)p, len, str, bufSize); + //printf("Created UTF-16 string from UTF-8 \"%s\":", in); //printHexData(1, str, buf->size(), 16, 1); //printf("\n"); diff --git a/libs/utils/String8.cpp b/libs/utils/String8.cpp index e908ec1..3a34838 100644 --- a/libs/utils/String8.cpp +++ b/libs/utils/String8.cpp @@ -208,10 +208,23 @@ static char* allocFromUTF16OrUTF32(const T* in, L len) return getEmptyString(); } -// Note: not dealing with expanding surrogate pairs. static char* allocFromUTF16(const char16_t* in, size_t len) { - return allocFromUTF16OrUTF32<char16_t, size_t>(in, len); + if (len == 0) return getEmptyString(); + + const size_t bytes = utf8_length_from_utf16(in, len); + + SharedBuffer* buf = SharedBuffer::alloc(bytes+1); + LOG_ASSERT(buf, "Unable to allocate shared buffer"); + if (buf) { + char* str = (char*)buf->data(); + + utf16_to_utf8(in, len, str, bytes+1); + + return str; + } + + return getEmptyString(); } static char* allocFromUTF32(const char32_t* in, size_t len) @@ -762,6 +775,26 @@ size_t utf8_length_from_utf32(const char32_t *src, size_t src_len) return ret; } +size_t utf8_length_from_utf16(const char16_t *src, size_t src_len) +{ + if (src == NULL || src_len == 0) { + return 0; + } + size_t ret = 0; + const char16_t* const end = src + src_len; + while (src < end) { + if ((*src & 0xFC00) == 0xD800 && (src + 1) < end + && (*++src & 0xFC00) == 0xDC00) { + // surrogate pairs are always 4 bytes. + ret += 4; + src++; + } else { + ret += android::utf32_to_utf8_bytes((char32_t) *src++); + } + } + return ret; +} + static int32_t utf32_at_internal(const char* cur, size_t *num_read) { const char first_char = *cur; @@ -848,3 +881,33 @@ size_t utf32_to_utf8(const char32_t* src, size_t src_len, } return cur - dst; } + +size_t utf16_to_utf8(const char16_t* src, size_t src_len, + char* dst, size_t dst_len) +{ + if (src == NULL || src_len == 0 || dst == NULL || dst_len == 0) { + return 0; + } + const char16_t* cur_utf16 = src; + const char16_t* const end_utf16 = src + src_len; + char *cur = dst; + const char* const end = dst + dst_len; + while (cur_utf16 < end_utf16 && cur < end) { + char32_t utf32; + // surrogate pairs + if ((*cur_utf16 & 0xFC00) == 0xD800 && (cur_utf16 + 1) < end_utf16) { + utf32 = (*cur_utf16++ - 0xD800) << 10; + utf32 |= *cur_utf16++ - 0xDC00; + utf32 += 0x10000; + } else { + utf32 = (char32_t) *cur_utf16++; + } + size_t len = android::utf32_to_utf8_bytes(utf32); + android::utf32_to_utf8((uint8_t*)cur, utf32, len); + cur += len; + } + if (cur < end) { + *cur = '\0'; + } + return cur - dst; +} diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp index ec3db09..2b1f490 100644 --- a/libs/utils/Threads.cpp +++ b/libs/utils/Threads.cpp @@ -20,6 +20,8 @@ #include <utils/threads.h> #include <utils/Log.h> +#include <cutils/sched_policy.h> + #include <stdio.h> #include <stdlib.h> #include <memory.h> @@ -269,6 +271,58 @@ void androidSetCreateThreadFunc(android_create_thread_fn func) gCreateThreadFn = func; } +pid_t androidGetTid() +{ +#ifdef HAVE_GETTID + return gettid(); +#else + return getpid(); +#endif +} + +int androidSetThreadSchedulingGroup(pid_t tid, int grp) +{ + if (grp > ANDROID_TGROUP_MAX || grp < 0) { + return BAD_VALUE; + } + +#if defined(HAVE_PTHREADS) + if (set_sched_policy(tid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ? + SP_BACKGROUND : SP_FOREGROUND)) { + return PERMISSION_DENIED; + } +#endif + + return NO_ERROR; +} + +int androidSetThreadPriority(pid_t tid, int pri) +{ + int rc = 0; + +#if defined(HAVE_PTHREADS) + int lasterr = 0; + + if (pri >= ANDROID_PRIORITY_BACKGROUND) { + rc = set_sched_policy(tid, SP_BACKGROUND); + } else if (getpriority(PRIO_PROCESS, tid) >= ANDROID_PRIORITY_BACKGROUND) { + rc = set_sched_policy(tid, SP_FOREGROUND); + } + + if (rc) { + lasterr = errno; + } + + if (setpriority(PRIO_PROCESS, tid, pri) < 0) { + rc = INVALID_OPERATION; + } else { + errno = lasterr; + } +#endif + + return rc; +} + namespace android { /* diff --git a/libs/utils/Unicode.cpp b/libs/utils/Unicode.cpp deleted file mode 100644 index f92703e..0000000 --- a/libs/utils/Unicode.cpp +++ /dev/null @@ -1,193 +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. - */ - -#include <utils/AndroidUnicode.h> -#include "CharacterData.h" - -#define LOG_TAG "Unicode" -#include <utils/Log.h> - -// ICU headers for using macros -#include <unicode/utf16.h> - -#define MIN_RADIX 2 -#define MAX_RADIX 36 - -#define TYPE_SHIFT 0 -#define TYPE_MASK ((1<<5)-1) - -#define DIRECTION_SHIFT (TYPE_SHIFT+5) -#define DIRECTION_MASK ((1<<5)-1) - -#define MIRRORED_SHIFT (DIRECTION_SHIFT+5) -#define MIRRORED_MASK ((1<<1)-1) - -#define TOUPPER_SHIFT (MIRRORED_SHIFT+1) -#define TOUPPER_MASK ((1<<6)-1) - -#define TOLOWER_SHIFT (TOUPPER_SHIFT+6) -#define TOLOWER_MASK ((1<<6)-1) - -#define TOTITLE_SHIFT (TOLOWER_SHIFT+6) -#define TOTITLE_MASK ((1<<2)-1) - -#define MIRROR_SHIFT (TOTITLE_SHIFT+2) -#define MIRROR_MASK ((1<<5)-1) - -#define NUMERIC_SHIFT (TOTITLE_SHIFT+2) -#define NUMERIC_MASK ((1<<7)-1) - -#define DECOMPOSITION_SHIFT (11) -#define DECOMPOSITION_MASK ((1<<5)-1) - -/* - * Returns the value stored in the CharacterData tables that contains - * an index into the packed data table and the decomposition type. - */ -static uint16_t findCharacterValue(UChar32 c) -{ - LOG_ASSERT(c >= 0 && c <= 0x10FFFF, "findCharacterValue received an invalid codepoint"); - if (c < 256) - return CharacterData::LATIN1_DATA[c]; - - // Rotate the bits because the tables are separated into even and odd codepoints - c = (c >> 1) | ((c & 1) << 20); - - CharacterData::Range search = CharacterData::FULL_DATA[c >> 16]; - const uint32_t* array = search.array; - - // This trick is so that that compare in the while loop does not - // need to shift the array entry down by 16 - c <<= 16; - c |= 0xFFFF; - - int high = (int)search.length - 1; - int low = 0; - - if (high < 0) - return 0; - - while (low < high - 1) - { - int probe = (high + low) >> 1; - - // The entries contain the codepoint in the high 16 bits and the index - // into PACKED_DATA in the low 16. - if (array[probe] > (unsigned)c) - high = probe; - else - low = probe; - } - - LOG_ASSERT((array[low] <= (unsigned)c), "A suitable range was not found"); - return array[low] & 0xFFFF; -} - -uint32_t android::Unicode::getPackedData(UChar32 c) -{ - // findCharacterValue returns a 16-bit value with the top 5 bits containing a decomposition type - // and the remaining bits containing an index. - return CharacterData::PACKED_DATA[findCharacterValue(c) & 0x7FF]; -} - -android::Unicode::CharType android::Unicode::getType(UChar32 c) -{ - if (c < 0 || c >= 0x10FFFF) - return CHARTYPE_UNASSIGNED; - return (CharType)((getPackedData(c) >> TYPE_SHIFT) & TYPE_MASK); -} - -android::Unicode::DecompositionType android::Unicode::getDecompositionType(UChar32 c) -{ - // findCharacterValue returns a 16-bit value with the top 5 bits containing a decomposition type - // and the remaining bits containing an index. - return (DecompositionType)((findCharacterValue(c) >> DECOMPOSITION_SHIFT) & DECOMPOSITION_MASK); -} - -int android::Unicode::getDigitValue(UChar32 c, int radix) -{ - if (radix < MIN_RADIX || radix > MAX_RADIX) - return -1; - - int tempValue = radix; - - if (c >= '0' && c <= '9') - tempValue = c - '0'; - else if (c >= 'a' && c <= 'z') - tempValue = c - 'a' + 10; - else if (c >= 'A' && c <= 'Z') - tempValue = c - 'A' + 10; - - return tempValue < radix ? tempValue : -1; -} - -int android::Unicode::getNumericValue(UChar32 c) -{ - if (isMirrored(c)) - return -1; - - return (int) CharacterData::NUMERICS[((getPackedData(c) >> NUMERIC_SHIFT) & NUMERIC_MASK)]; -} - -UChar32 android::Unicode::toLower(UChar32 c) -{ - return c + CharacterData::LCDIFF[(getPackedData(c) >> TOLOWER_SHIFT) & TOLOWER_MASK]; -} - -UChar32 android::Unicode::toUpper(UChar32 c) -{ - return c + CharacterData::UCDIFF[(getPackedData(c) >> TOUPPER_SHIFT) & TOUPPER_MASK]; -} - -android::Unicode::Direction android::Unicode::getDirectionality(UChar32 c) -{ - uint32_t data = getPackedData(c); - - if (0 == data) - return DIRECTIONALITY_UNDEFINED; - - Direction d = (Direction) ((data >> DIRECTION_SHIFT) & DIRECTION_MASK); - - if (DIRECTION_MASK == d) - return DIRECTIONALITY_UNDEFINED; - - return d; -} - -bool android::Unicode::isMirrored(UChar32 c) -{ - return ((getPackedData(c) >> MIRRORED_SHIFT) & MIRRORED_MASK) != 0; -} - -UChar32 android::Unicode::toMirror(UChar32 c) -{ - if (!isMirrored(c)) - return c; - - return c + CharacterData::MIRROR_DIFF[(getPackedData(c) >> MIRROR_SHIFT) & MIRROR_MASK]; -} - -UChar32 android::Unicode::toTitle(UChar32 c) -{ - int32_t diff = CharacterData::TCDIFF[(getPackedData(c) >> TOTITLE_SHIFT) & TOTITLE_MASK]; - - if (TOTITLE_MASK == diff) - return toUpper(c); - - return c + diff; -} - - diff --git a/libs/utils/VectorImpl.cpp b/libs/utils/VectorImpl.cpp index 2c2d667..0322af7 100644 --- a/libs/utils/VectorImpl.cpp +++ b/libs/utils/VectorImpl.cpp @@ -173,9 +173,10 @@ status_t VectorImpl::sort(VectorImpl::compar_r_t cmp, void* state) if (!array) return NO_MEMORY; temp = malloc(mItemSize); if (!temp) return NO_MEMORY; - _do_construct(temp, 1); item = reinterpret_cast<char*>(array) + mItemSize*(i); curr = reinterpret_cast<char*>(array) + mItemSize*(i-1); + } else { + _do_destroy(temp, 1); } _do_copy(temp, item, 1); @@ -183,12 +184,14 @@ status_t VectorImpl::sort(VectorImpl::compar_r_t cmp, void* state) ssize_t j = i-1; void* next = reinterpret_cast<char*>(array) + mItemSize*(i); do { + _do_destroy(next, 1); _do_copy(next, curr, 1); next = curr; --j; curr = reinterpret_cast<char*>(array) + mItemSize*(j); } while (j>=0 && (cmp(curr, temp, state) > 0)); + _do_destroy(next, 1); _do_copy(next, temp, 1); } i++; |