Merge commit 'remotes/korg/cupcake' into merge
Conflicts:
core/java/android/view/animation/TranslateAnimation.java
core/jni/Android.mk
core/res/res/values-en-rGB/strings.xml
libs/audioflinger/AudioFlinger.cpp
libs/surfaceflinger/LayerScreenshot.cpp
packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/libs/audioflinger/A2dpAudioInterface.cpp
index c8c8431..2974e32 100644
--- a/libs/audioflinger/A2dpAudioInterface.cpp
+++ b/libs/audioflinger/A2dpAudioInterface.cpp
@@ -48,7 +48,6 @@
int format, int channelCount, uint32_t sampleRate, status_t *status)
{
LOGD("A2dpAudioInterface::openOutputStream %d, %d, %d\n", format, channelCount, sampleRate);
- Mutex::Autolock lock(mLock);
status_t err = 0;
// only one output stream allowed
@@ -72,7 +71,8 @@
}
AudioStreamIn* A2dpAudioInterface::openInputStream(
- int format, int channelCount, uint32_t sampleRate, status_t *status)
+ int format, int channelCount, uint32_t sampleRate, status_t *status,
+ AudioSystem::audio_in_acoustics acoustics)
{
if (status)
*status = -1;
@@ -99,6 +99,10 @@
if (strcmp(key, "a2dp_sink_address") == 0) {
return mOutput->setAddress(value);
}
+ if (strcmp(key, "bluetooth_enabled") == 0 &&
+ strcmp(value, "false") == 0) {
+ return mOutput->close();
+ }
return 0;
}
@@ -126,11 +130,11 @@
// ----------------------------------------------------------------------------
A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() :
- mFd(-1), mStandby(true), mStartCount(0), mRetryCount(0), mData(NULL),
- mInitialized(false)
+ mFd(-1), mStandby(true), mStartCount(0), mRetryCount(0), mData(NULL)
{
// use any address by default
- strncpy(mA2dpAddress, "00:00:00:00:00:00", sizeof(mA2dpAddress));
+ strcpy(mA2dpAddress, "00:00:00:00:00:00");
+ init();
}
status_t A2dpAudioInterface::A2dpAudioStreamOut::set(
@@ -154,23 +158,17 @@
A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut()
{
- if (mData)
- a2dp_cleanup(mData);
+ close();
}
ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes)
{
- status_t status = NO_INIT;
- size_t remaining = bytes;
+ Mutex::Autolock lock(mLock);
- if (!mInitialized) {
- status = a2dp_init(mA2dpAddress, 44100, 2, &mData);
- if (status < 0) {
- LOGE("a2dp_init failed err: %d\n", status);
- goto Error;
- }
- mInitialized = true;
- }
+ size_t remaining = bytes;
+ status_t status = init();
+ if (status < 0)
+ goto Error;
while (remaining > 0) {
status = a2dp_write(mData, buffer, remaining);
@@ -186,17 +184,34 @@
return bytes;
-Error:
+Error:
// Simulate audio output timing in case of error
usleep(bytes * 1000000 / frameSize() / sampleRate());
return status;
}
+status_t A2dpAudioInterface::A2dpAudioStreamOut::init()
+{
+ if (!mData) {
+ status_t status = a2dp_init(44100, 2, &mData);
+ if (status < 0) {
+ LOGE("a2dp_init failed err: %d\n", status);
+ mData = NULL;
+ return status;
+ }
+ a2dp_set_sink(mData, mA2dpAddress);
+ }
+
+ return 0;
+}
+
status_t A2dpAudioInterface::A2dpAudioStreamOut::standby()
{
int result = 0;
+ Mutex::Autolock lock(mLock);
+
if (!mStandby) {
result = a2dp_stop(mData);
if (result == 0)
@@ -208,19 +223,24 @@
status_t A2dpAudioInterface::A2dpAudioStreamOut::setAddress(const char* address)
{
- if (strlen(address) < sizeof(mA2dpAddress))
+ Mutex::Autolock lock(mLock);
+
+ if (strlen(address) != strlen("00:00:00:00:00:00"))
return -EINVAL;
- if (strcmp(address, mA2dpAddress)) {
- strcpy(mA2dpAddress, address);
-
- if (mInitialized) {
- a2dp_cleanup(mData);
- mData = NULL;
- mInitialized = false;
- }
+ strcpy(mA2dpAddress, address);
+ if (mData)
+ a2dp_set_sink(mData, mA2dpAddress);
+
+ return NO_ERROR;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::close()
+{
+ if (mData) {
+ a2dp_cleanup(mData);
+ mData = NULL;
}
-
return NO_ERROR;
}
diff --git a/libs/audioflinger/A2dpAudioInterface.h b/libs/audioflinger/A2dpAudioInterface.h
index 2197d0e..99614dc 100644
--- a/libs/audioflinger/A2dpAudioInterface.h
+++ b/libs/audioflinger/A2dpAudioInterface.h
@@ -58,7 +58,8 @@
int format,
int channelCount,
uint32_t sampleRate,
- status_t *status);
+ status_t *status,
+ AudioSystem::audio_in_acoustics acoustics);
protected:
virtual status_t doRouting();
@@ -77,7 +78,7 @@
virtual size_t bufferSize() const { return 512 * 20; }
virtual int channelCount() const { return 2; }
virtual int format() const { return AudioSystem::PCM_16_BIT; }
- virtual uint32_t latency() const { return ((1000*channelCount()*bufferSize())/frameSize())/sampleRate() + 200; }
+ virtual uint32_t latency() const { return ((1000*bufferSize())/frameSize())/sampleRate() + 200; }
virtual status_t setVolume(float volume) { return INVALID_OPERATION; }
virtual ssize_t write(const void* buffer, size_t bytes);
status_t standby();
@@ -85,6 +86,8 @@
private:
friend class A2dpAudioInterface;
+ status_t init();
+ status_t close();
status_t setAddress(const char* address);
private:
@@ -94,10 +97,9 @@
int mRetryCount;
char mA2dpAddress[20];
void* mData;
- bool mInitialized;
+ Mutex mLock;
};
- Mutex mLock;
A2dpAudioStreamOut* mOutput;
};
diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h
index 42204d6..9a94102 100644
--- a/libs/audioflinger/AudioDumpInterface.h
+++ b/libs/audioflinger/AudioDumpInterface.h
@@ -78,8 +78,9 @@
virtual status_t setParameter(const char* key, const char* value)
{return mFinalInterface->setParameter(key, value);}
- virtual AudioStreamIn* openInputStream( int format, int channelCount, uint32_t sampleRate, status_t *status)
- {return mFinalInterface->openInputStream( format, channelCount, sampleRate, status);}
+ virtual AudioStreamIn* openInputStream( int format, int channelCount, uint32_t sampleRate, status_t *status,
+ AudioSystem::audio_in_acoustics acoustics)
+ {return mFinalInterface->openInputStream( format, channelCount, sampleRate, status, acoustics);}
virtual status_t dump(int fd, const Vector<String16>& args) { return mFinalInterface->dumpState(fd, args); }
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 918b01f..3c81a47 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -47,6 +47,15 @@
#include "A2dpAudioInterface.h"
#endif
+// ----------------------------------------------------------------------------
+// the sim build doesn't have gettid
+
+#ifndef HAVE_GETTID
+# define gettid getpid
+#endif
+
+// ----------------------------------------------------------------------------
+
namespace android {
//static const nsecs_t kStandbyTimeInNsecs = seconds(3);
@@ -59,6 +68,16 @@
static const int8_t kMaxTrackRetries = 50;
static const int8_t kMaxTrackStartupRetries = 50;
+static const int kStartSleepTime = 30000;
+static const int kStopSleepTime = 30000;
+
+static const int kDumpLockRetries = 50;
+static const int kDumpLockSleep = 20000;
+
+// Maximum number of pending buffers allocated by OutputTrack::write()
+static const uint8_t kMaxOutputTrackBuffers = 5;
+
+
#define AUDIOFLINGER_SECURITY_ENABLED 1
// ----------------------------------------------------------------------------
@@ -98,13 +117,10 @@
// ----------------------------------------------------------------------------
AudioFlinger::AudioFlinger()
- : BnAudioFlinger(), Thread(false),
- mMasterVolume(0), mMasterMute(true), mHardwareAudioMixer(0), mA2dpAudioMixer(0),
- mAudioMixer(0), mAudioHardware(0), mA2dpAudioInterface(0), mHardwareOutput(0),
- mA2dpOutput(0), mOutput(0), mRequestedOutput(0), mAudioRecordThread(0),
- mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0), mMixBuffer(0),
- mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mStandby(false),
- mInWrite(false), mA2dpDisableCount(0), mA2dpSuppressed(false)
+ : BnAudioFlinger(),
+ mAudioHardware(0), mA2dpAudioInterface(0), mA2dpEnabled(false), mNotifyA2dpChange(false),
+ mForcedSpeakerCount(0), mA2dpDisableCount(0), mA2dpSuppressed(false), mForcedRoute(0),
+ mRouteRestoreTime(0), mMusicMuteSaved(false)
{
mHardwareStatus = AUDIO_HW_IDLE;
mAudioHardware = AudioHardwareInterface::create();
@@ -113,57 +129,51 @@
// open 16-bit output stream for s/w mixer
mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
status_t status;
- mHardwareOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
+ AudioStreamOut *hwOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
mHardwareStatus = AUDIO_HW_IDLE;
- if (mHardwareOutput) {
- mHardwareAudioMixer = new AudioMixer(getOutputFrameCount(mHardwareOutput), mHardwareOutput->sampleRate());
- mRequestedOutput = mHardwareOutput;
- doSetOutput(mHardwareOutput);
-
- // FIXME - this should come from settings
- setMasterVolume(1.0f);
- setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
- setRouting(AudioSystem::MODE_RINGTONE, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
- setRouting(AudioSystem::MODE_IN_CALL, AudioSystem::ROUTE_EARPIECE, AudioSystem::ROUTE_ALL);
- setMode(AudioSystem::MODE_NORMAL);
- mMasterMute = false;
+ if (hwOutput) {
+ mHardwareMixerThread = new MixerThread(this, hwOutput, AudioSystem::AUDIO_OUTPUT_HARDWARE);
} else {
- LOGE("Failed to initialize output stream, status: %d", status);
+ LOGE("Failed to initialize hardware output stream, status: %d", status);
}
#ifdef WITH_A2DP
// Create A2DP interface
mA2dpAudioInterface = new A2dpAudioInterface();
- mA2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
- mA2dpAudioMixer = new AudioMixer(getOutputFrameCount(mA2dpOutput), mA2dpOutput->sampleRate());
-
- // create a buffer big enough for both hardware and A2DP audio output.
- size_t hwFrameCount = getOutputFrameCount(mHardwareOutput);
- size_t a2dpFrameCount = getOutputFrameCount(mA2dpOutput);
- size_t frameCount = (hwFrameCount > a2dpFrameCount ? hwFrameCount : a2dpFrameCount);
-#else
- size_t frameCount = getOutputFrameCount(mHardwareOutput);
+ AudioStreamOut *a2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
+ if (a2dpOutput) {
+ mA2dpMixerThread = new MixerThread(this, a2dpOutput, AudioSystem::AUDIO_OUTPUT_A2DP);
+ if (hwOutput) {
+ uint32_t frameCount = ((a2dpOutput->bufferSize()/a2dpOutput->frameSize()) * hwOutput->sampleRate()) / a2dpOutput->sampleRate();
+ MixerThread::OutputTrack *a2dpOutTrack = new MixerThread::OutputTrack(mA2dpMixerThread,
+ hwOutput->sampleRate(),
+ AudioSystem::PCM_16_BIT,
+ hwOutput->channelCount(),
+ frameCount);
+ mHardwareMixerThread->setOuputTrack(a2dpOutTrack);
+ }
+ } else {
+ LOGE("Failed to initialize A2DP output stream, status: %d", status);
+ }
#endif
- // FIXME - Current mixer implementation only supports stereo output: Always
- // Allocate a stereo buffer even if HW output is mono.
- mMixBuffer = new int16_t[frameCount * 2];
- memset(mMixBuffer, 0, frameCount * 2 * sizeof(int16_t));
-
+
+ // FIXME - this should come from settings
+ setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
+ setRouting(AudioSystem::MODE_RINGTONE, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
+ setRouting(AudioSystem::MODE_IN_CALL, AudioSystem::ROUTE_EARPIECE, AudioSystem::ROUTE_ALL);
+ setMode(AudioSystem::MODE_NORMAL);
+
+ setMasterVolume(1.0f);
+ setMasterMute(false);
+
// Start record thread
- mAudioRecordThread = new AudioRecordThread(mAudioHardware);
+ mAudioRecordThread = new AudioRecordThread(mAudioHardware, this);
if (mAudioRecordThread != 0) {
mAudioRecordThread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO);
}
} else {
LOGE("Couldn't even initialize the stubbed audio hardware!");
}
-
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.audio.silent", value, "0");
- if (atoi(value)) {
- LOGD("Silence is golden");
- mMasterMute = true;
- }
}
AudioFlinger::~AudioFlinger()
@@ -172,60 +182,73 @@
mAudioRecordThread->exit();
mAudioRecordThread.clear();
}
+ mHardwareMixerThread.clear();
delete mAudioHardware;
// deleting mA2dpAudioInterface also deletes mA2dpOutput;
+#ifdef WITH_A2DP
+ mA2dpMixerThread.clear();
delete mA2dpAudioInterface;
- delete [] mMixBuffer;
- delete mHardwareAudioMixer;
- delete mA2dpAudioMixer;
-}
-
-void AudioFlinger::setOutput(AudioStreamOut* output)
-{
- mRequestedOutput = output;
+#endif
}
-void AudioFlinger::doSetOutput(AudioStreamOut* output)
-{
- mSampleRate = output->sampleRate();
- mChannelCount = output->channelCount();
-
- // FIXME - Current mixer implementation only supports stereo output
- if (mChannelCount == 1) {
- LOGE("Invalid audio hardware channel count");
- }
- mFormat = output->format();
- mFrameCount = getOutputFrameCount(output);
- mAudioMixer = (output == mA2dpOutput ? mA2dpAudioMixer : mHardwareAudioMixer);
- mOutput = output;
-}
-
-size_t AudioFlinger::getOutputFrameCount(AudioStreamOut* output)
-{
- return output->bufferSize() / output->channelCount() / sizeof(int16_t);
-}
#ifdef WITH_A2DP
-bool AudioFlinger::streamDisablesA2dp(int streamType)
+// setA2dpEnabled_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::setA2dpEnabled_l(bool enable)
{
- return (streamType == AudioTrack::SYSTEM ||
- streamType == AudioTrack::RING ||
- streamType == AudioTrack::ALARM ||
- streamType == AudioTrack::NOTIFICATION);
+ SortedVector < sp<MixerThread::Track> > tracks;
+ SortedVector < wp<MixerThread::Track> > activeTracks;
+
+ LOGV_IF(enable, "set output to A2DP\n");
+ LOGV_IF(!enable, "set output to hardware audio\n");
+
+ // Transfer tracks playing on MUSIC stream from one mixer to the other
+ if (enable) {
+ mHardwareMixerThread->getTracks_l(tracks, activeTracks);
+ mA2dpMixerThread->putTracks_l(tracks, activeTracks);
+ } else {
+ mA2dpMixerThread->getTracks_l(tracks, activeTracks);
+ mHardwareMixerThread->putTracks_l(tracks, activeTracks);
+ }
+ mA2dpEnabled = enable;
+ mNotifyA2dpChange = true;
+ mWaitWorkCV.broadcast();
}
-void AudioFlinger::setA2dpEnabled(bool enable)
+// checkA2dpEnabledChange_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::checkA2dpEnabledChange_l()
{
- if (enable) {
- LOGD("set output to A2DP\n");
- setOutput(mA2dpOutput);
- } else {
- LOGD("set output to hardware audio\n");
- setOutput(mHardwareOutput);
+ if (mNotifyA2dpChange) {
+ // Notify AudioSystem of the A2DP activation/deactivation
+ size_t size = mNotificationClients.size();
+ for (size_t i = 0; i < size; i++) {
+ sp<IBinder> binder = mNotificationClients.itemAt(i).promote();
+ if (binder != NULL) {
+ LOGV("Notifying output change to client %p", binder.get());
+ sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder);
+ client->a2dpEnabledChanged(mA2dpEnabled);
+ }
+ }
+ mNotifyA2dpChange = false;
}
}
#endif // WITH_A2DP
+bool AudioFlinger::streamForcedToSpeaker(int streamType)
+{
+ // NOTE that streams listed here must not be routed to A2DP by default:
+ // AudioSystem::routedToA2dpOutput(streamType) == false
+ return (streamType == AudioSystem::RING ||
+ streamType == AudioSystem::ALARM ||
+ streamType == AudioSystem::NOTIFICATION);
+}
+
+bool AudioFlinger::streamDisablesA2dp(int streamType)
+{
+ return (streamType == AudioSystem::VOICE_CALL ||
+ streamType == AudioSystem::BLUETOOTH_SCO);
+}
+
status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
@@ -247,60 +270,18 @@
return NO_ERROR;
}
-status_t AudioFlinger::dumpTracks(int fd, const Vector<String16>& args)
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- result.append("Tracks:\n");
- result.append(" Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
- for (size_t i = 0; i < mTracks.size(); ++i) {
- wp<Track> wTrack = mTracks[i];
- if (wTrack != 0) {
- sp<Track> track = wTrack.promote();
- if (track != 0) {
- track->dump(buffer, SIZE);
- result.append(buffer);
- }
- }
- }
-
- result.append("Active Tracks:\n");
- result.append(" Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
- for (size_t i = 0; i < mActiveTracks.size(); ++i) {
- wp<Track> wTrack = mTracks[i];
- if (wTrack != 0) {
- sp<Track> track = wTrack.promote();
- if (track != 0) {
- track->dump(buffer, SIZE);
- result.append(buffer);
- }
- }
- }
- write(fd, result.string(), result.size());
- return NO_ERROR;
-}
status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
-
- snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", audioMixer()->trackNames());
- result.append(buffer);
- snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
- result.append(buffer);
- snprintf(buffer, SIZE, "total writes: %d\n", mNumWrites);
- result.append(buffer);
- snprintf(buffer, SIZE, "delayed writes: %d\n", mNumDelayedWrites);
- result.append(buffer);
- snprintf(buffer, SIZE, "blocked in write: %d\n", mInWrite);
- result.append(buffer);
- snprintf(buffer, SIZE, "standby: %d\n", mStandby);
- result.append(buffer);
- snprintf(buffer, SIZE, "Hardware status: %d\n", mHardwareStatus);
+ int hardwareStatus = mHardwareStatus;
+
+ if (hardwareStatus == AUDIO_HW_IDLE && mHardwareMixerThread->mStandby) {
+ hardwareStatus = AUDIO_HW_STANDBY;
+ }
+ snprintf(buffer, SIZE, "Hardware status: %d\n", hardwareStatus);
result.append(buffer);
write(fd, result.string(), result.size());
return NO_ERROR;
@@ -325,225 +306,36 @@
if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
dumpPermissionDenial(fd, args);
} else {
- AutoMutex lock(&mLock);
+ bool locked = false;
+ for (int i = 0; i < kDumpLockRetries; ++i) {
+ if (mLock.tryLock() == NO_ERROR) {
+ locked = true;
+ break;
+ }
+ usleep(kDumpLockSleep);
+ }
dumpClients(fd, args);
- dumpTracks(fd, args);
dumpInternals(fd, args);
+ mHardwareMixerThread->dump(fd, args);
+#ifdef WITH_A2DP
+ mA2dpMixerThread->dump(fd, args);
+#endif
+
+ // dump record client
+ if (mAudioRecordThread != 0) mAudioRecordThread->dump(fd, args);
+
if (mAudioHardware) {
mAudioHardware->dumpState(fd, args);
}
+ if (locked) mLock.unlock();
}
return NO_ERROR;
}
-// Thread virtuals
-bool AudioFlinger::threadLoop()
-{
- unsigned long sleepTime = kBufferRecoveryInUsecs;
- int16_t* curBuf = mMixBuffer;
- Vector< sp<Track> > tracksToRemove;
- size_t enabledTracks = 0;
- nsecs_t standbyTime = systemTime();
-
- do {
- enabledTracks = 0;
- { // scope for the mLock
-
- Mutex::Autolock _l(mLock);
- const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
-
- // put audio hardware into standby after short delay
- if UNLIKELY(!activeTracks.size() && systemTime() > standbyTime) {
- // wait until we have something to do...
- LOGV("Audio hardware entering standby\n");
- mHardwareStatus = AUDIO_HW_STANDBY;
- if (!mStandby) {
- mOutput->standby();
- mStandby = true;
- }
- mHardwareStatus = AUDIO_HW_IDLE;
- // we're about to wait, flush the binder command buffer
- IPCThreadState::self()->flushCommands();
- mWaitWorkCV.wait(mLock);
- LOGV("Audio hardware exiting standby\n");
- standbyTime = systemTime() + kStandbyTimeInNsecs;
- continue;
- }
-
- // check for change in output
- if (mRequestedOutput != mOutput) {
-
- // put current output into standby mode
- if (mOutput) mOutput->standby();
-
- // change output
- doSetOutput(mRequestedOutput);
- }
-
- // find out which tracks need to be processed
- size_t count = activeTracks.size();
- for (size_t i=0 ; i<count ; i++) {
- sp<Track> t = activeTracks[i].promote();
- if (t == 0) continue;
-
- Track* const track = t.get();
- audio_track_cblk_t* cblk = track->cblk();
-
- // The first time a track is added we wait
- // for all its buffers to be filled before processing it
- mAudioMixer->setActiveTrack(track->name());
- if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
- !track->isPaused())
- {
- //LOGD("u=%08x, s=%08x [OK]", u, s);
-
- // compute volume for this track
- int16_t left, right;
- if (track->isMuted() || mMasterMute || track->isPausing()) {
- left = right = 0;
- if (track->isPausing()) {
- LOGV("paused(%d)", track->name());
- track->setPaused();
- }
- } else {
- float typeVolume = mStreamTypes[track->type()].volume;
- float v = mMasterVolume * typeVolume;
- float v_clamped = v * cblk->volume[0];
- if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
- left = int16_t(v_clamped);
- v_clamped = v * cblk->volume[1];
- if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
- right = int16_t(v_clamped);
- }
-
- // XXX: these things DON'T need to be done each time
- mAudioMixer->setBufferProvider(track);
- mAudioMixer->enable(AudioMixer::MIXING);
-
- int param;
- if ( track->mFillingUpStatus == Track::FS_FILLED) {
- // no ramp for the first volume setting
- track->mFillingUpStatus = Track::FS_ACTIVE;
- if (track->mState == TrackBase::RESUMING) {
- track->mState = TrackBase::ACTIVE;
- param = AudioMixer::RAMP_VOLUME;
- } else {
- param = AudioMixer::VOLUME;
- }
- } else {
- param = AudioMixer::RAMP_VOLUME;
- }
- mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left);
- mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right);
- mAudioMixer->setParameter(
- AudioMixer::TRACK,
- AudioMixer::FORMAT, track->format());
- mAudioMixer->setParameter(
- AudioMixer::TRACK,
- AudioMixer::CHANNEL_COUNT, track->channelCount());
- mAudioMixer->setParameter(
- AudioMixer::RESAMPLE,
- AudioMixer::SAMPLE_RATE,
- int(cblk->sampleRate));
-
- // reset retry count
- track->mRetryCount = kMaxTrackRetries;
- enabledTracks++;
- } else {
- //LOGD("u=%08x, s=%08x [NOT READY]", u, s);
- if (track->isStopped()) {
- track->reset();
- }
- if (track->isTerminated() || track->isStopped() || track->isPaused()) {
- // We have consumed all the buffers of this track.
- // Remove it from the list of active tracks.
- LOGV("remove(%d) from active list", track->name());
- tracksToRemove.add(track);
- } else {
- // No buffers for this track. Give it a few chances to
- // fill a buffer, then remove it from active list.
- if (--(track->mRetryCount) <= 0) {
- LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
- tracksToRemove.add(track);
- }
- }
- // LOGV("disable(%d)", track->name());
- mAudioMixer->disable(AudioMixer::MIXING);
- }
- }
-
- // remove all the tracks that need to be...
- count = tracksToRemove.size();
- if (UNLIKELY(count)) {
- for (size_t i=0 ; i<count ; i++) {
- const sp<Track>& track = tracksToRemove[i];
- removeActiveTrack(track);
- if (track->isTerminated()) {
- mTracks.remove(track);
- mAudioMixer->deleteTrackName(track->mName);
- }
- }
- }
- }
- if (LIKELY(enabledTracks)) {
- // mix buffers...
- mAudioMixer->process(curBuf);
-
- // output audio to hardware
- mLastWriteTime = systemTime();
- mInWrite = true;
- size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t);
- mOutput->write(curBuf, mixBufferSize);
- mNumWrites++;
- mInWrite = false;
- mStandby = false;
- nsecs_t temp = systemTime();
- standbyTime = temp + kStandbyTimeInNsecs;
- nsecs_t delta = temp - mLastWriteTime;
- nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
- if (delta > maxPeriod) {
- LOGW("write blocked for %llu msecs", ns2ms(delta));
- mNumDelayedWrites++;
- }
- sleepTime = kBufferRecoveryInUsecs;
- } else {
- // There was nothing to mix this round, which means all
- // active tracks were late. Sleep a little bit to give
- // them another chance. If we're too late, the audio
- // hardware will zero-fill for us.
- LOGV("no buffers - usleep(%lu)", sleepTime);
- usleep(sleepTime);
- if (sleepTime < kMaxBufferRecoveryInUsecs) {
- sleepTime += kBufferRecoveryInUsecs;
- }
- }
-
- // finally let go of all our tracks, without the lock held
- // since we can't guarantee the destructors won't acquire that
- // same lock.
- tracksToRemove.clear();
- } while (true);
-
- return false;
-}
-
-status_t AudioFlinger::readyToRun()
-{
- if (mSampleRate == 0) {
- LOGE("No working audio driver found.");
- return NO_INIT;
- }
- LOGI("AudioFlinger's main thread ready to run.");
- return NO_ERROR;
-}
-
-void AudioFlinger::onFirstRef()
-{
- run("AudioFlinger", ANDROID_PRIORITY_URGENT_AUDIO);
-}
-
// IAudioFlinger interface
+
+
sp<IAudioTrack> AudioFlinger::createTrack(
pid_t pid,
int streamType,
@@ -555,34 +347,21 @@
const sp<IMemory>& sharedBuffer,
status_t *status)
{
- sp<Track> track;
+ sp<MixerThread::Track> track;
sp<TrackHandle> trackHandle;
sp<Client> client;
wp<Client> wclient;
status_t lStatus;
- if (streamType >= AudioTrack::NUM_STREAM_TYPES) {
+ if (streamType >= AudioSystem::NUM_STREAM_TYPES) {
LOGE("invalid stream type");
lStatus = BAD_VALUE;
goto Exit;
}
- // Resampler implementation limits input sampling rate to 2 x output sampling rate.
- if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) {
- LOGE("Sample rate out of range: %d", sampleRate);
- lStatus = BAD_VALUE;
- goto Exit;
- }
-
{
Mutex::Autolock _l(mLock);
- if (mSampleRate == 0) {
- LOGE("Audio driver not initialized.");
- lStatus = NO_INIT;
- goto Exit;
- }
-
wclient = mClients.valueFor(pid);
if (wclient != NULL) {
@@ -591,13 +370,21 @@
client = new Client(this, pid);
mClients.add(pid, client);
}
-
- track = new Track(this, client, streamType, sampleRate, format,
- channelCount, frameCount, sharedBuffer);
- mTracks.add(track);
+#ifdef WITH_A2DP
+ if (isA2dpEnabled() && AudioSystem::routedToA2dpOutput(streamType)) {
+ track = mA2dpMixerThread->createTrack_l(client, streamType, sampleRate, format,
+ channelCount, frameCount, sharedBuffer, &lStatus);
+ } else
+#endif
+ {
+ track = mHardwareMixerThread->createTrack_l(client, streamType, sampleRate, format,
+ channelCount, frameCount, sharedBuffer, &lStatus);
+ }
+ }
+ if (lStatus == NO_ERROR) {
trackHandle = new TrackHandle(track);
-
- lStatus = NO_ERROR;
+ } else {
+ track.clear();
}
Exit:
@@ -607,34 +394,54 @@
return trackHandle;
}
-uint32_t AudioFlinger::sampleRate() const
+uint32_t AudioFlinger::sampleRate(int output) const
{
- return mSampleRate;
+#ifdef WITH_A2DP
+ if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+ return mA2dpMixerThread->sampleRate();
+ }
+#endif
+ return mHardwareMixerThread->sampleRate();
}
-int AudioFlinger::channelCount() const
+int AudioFlinger::channelCount(int output) const
{
- return mChannelCount;
+#ifdef WITH_A2DP
+ if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+ return mA2dpMixerThread->channelCount();
+ }
+#endif
+ return mHardwareMixerThread->channelCount();
}
-int AudioFlinger::format() const
+int AudioFlinger::format(int output) const
{
- return mFormat;
+#ifdef WITH_A2DP
+ if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+ return mA2dpMixerThread->format();
+ }
+#endif
+ return mHardwareMixerThread->format();
}
-size_t AudioFlinger::frameCount() const
+size_t AudioFlinger::frameCount(int output) const
{
- return mFrameCount;
+#ifdef WITH_A2DP
+ if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+ return mA2dpMixerThread->frameCount();
+ }
+#endif
+ return mHardwareMixerThread->frameCount();
}
-uint32_t AudioFlinger::latency() const
+uint32_t AudioFlinger::latency(int output) const
{
- if (mOutput) {
- return mOutput->latency();
- }
- else {
- return 0;
- }
+#ifdef WITH_A2DP
+ if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+ return mA2dpMixerThread->latency();
+ }
+#endif
+ return mHardwareMixerThread->latency();
}
status_t AudioFlinger::setMasterVolume(float value)
@@ -648,12 +455,14 @@
AutoMutex lock(mHardwareLock);
mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
if (mAudioHardware->setMasterVolume(value) == NO_ERROR) {
- mMasterVolume = 1.0f;
- }
- else {
- mMasterVolume = value;
+ value = 1.0f;
}
mHardwareStatus = AUDIO_HW_IDLE;
+ mHardwareMixerThread->setMasterVolume(value);
+#ifdef WITH_A2DP
+ mA2dpMixerThread->setMasterVolume(value);
+#endif
+
return NO_ERROR;
}
@@ -671,20 +480,21 @@
}
#ifdef WITH_A2DP
- LOGD("setRouting %d %d %d\n", mode, routes, mask);
+ LOGD("setRouting %d %d %d, tid %d, calling tid %d\n", mode, routes, mask, gettid(), IPCThreadState::self()->getCallingPid());
if (mode == AudioSystem::MODE_NORMAL &&
(mask & AudioSystem::ROUTE_BLUETOOTH_A2DP)) {
AutoMutex lock(&mLock);
bool enableA2dp = false;
if (routes & AudioSystem::ROUTE_BLUETOOTH_A2DP) {
- if (mA2dpDisableCount > 0)
- mA2dpSuppressed = true;
- else
- enableA2dp = true;
+ enableA2dp = true;
}
- setA2dpEnabled(enableA2dp);
- LOGD("setOutput done\n");
+ if (mA2dpDisableCount > 0) {
+ mA2dpSuppressed = enableA2dp;
+ } else {
+ setA2dpEnabled_l(enableA2dp);
+ }
+ LOGV("setOutput done\n");
}
#endif
@@ -697,6 +507,12 @@
err = mAudioHardware->getRouting(mode, &r);
if (err == NO_ERROR) {
r = (r & ~mask) | (routes & mask);
+ if (mode == AudioSystem::MODE_NORMAL ||
+ (mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) {
+ mSavedRoute = r;
+ r |= mForcedRoute;
+ LOGV("setRouting mSavedRoute %08x mForcedRoute %08x\n", mSavedRoute, mForcedRoute);
+ }
mHardwareStatus = AUDIO_HW_SET_ROUTING;
err = mAudioHardware->setRouting(mode, r);
}
@@ -709,9 +525,14 @@
{
uint32_t routes = 0;
if ((mode >= AudioSystem::MODE_CURRENT) && (mode < AudioSystem::NUM_MODES)) {
- mHardwareStatus = AUDIO_HW_GET_ROUTING;
- mAudioHardware->getRouting(mode, &routes);
- mHardwareStatus = AUDIO_HW_IDLE;
+ if (mode == AudioSystem::MODE_NORMAL ||
+ (mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) {
+ routes = mSavedRoute;
+ } else {
+ mHardwareStatus = AUDIO_HW_GET_ROUTING;
+ mAudioHardware->getRouting(mode, &routes);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ }
} else {
LOGW("Illegal value: getRouting(%d)", mode);
}
@@ -774,19 +595,21 @@
if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
-
- mMasterMute = muted;
+ mHardwareMixerThread->setMasterMute(muted);
+#ifdef WITH_A2DP
+ mA2dpMixerThread->setMasterMute(muted);
+#endif
return NO_ERROR;
}
float AudioFlinger::masterVolume() const
{
- return mMasterVolume;
+ return mHardwareMixerThread->masterVolume();
}
bool AudioFlinger::masterMute() const
{
- return mMasterMute;
+ return mHardwareMixerThread->masterMute();
}
status_t AudioFlinger::setStreamVolume(int stream, float value)
@@ -796,26 +619,40 @@
return PERMISSION_DENIED;
}
- if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+ if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
return BAD_VALUE;
}
status_t ret = NO_ERROR;
- if (stream == AudioTrack::VOICE_CALL) {
+
+ if (stream == AudioSystem::VOICE_CALL ||
+ stream == AudioSystem::BLUETOOTH_SCO) {
+ float hwValue = value;
+ if (stream == AudioSystem::VOICE_CALL) {
+ hwValue = (float)AudioSystem::logToLinear(value)/100.0f;
+ // FIXME: This is a temporary fix to re-base the internally
+ // generated in-call audio so that it is never muted, which is
+ // already the case for the hardware routed in-call audio.
+ // When audio stream handling is reworked, this should be
+ // addressed more cleanly. Fixes #1324; see discussion at
+ // http://review.source.android.com/8224
+ value = value * 0.99 + 0.01;
+ } else { // (type == AudioSystem::BLUETOOTH_SCO)
+ hwValue = 1.0f;
+ }
+
AutoMutex lock(mHardwareLock);
mHardwareStatus = AUDIO_SET_VOICE_VOLUME;
- ret = mAudioHardware->setVoiceVolume(value);
+ ret = mAudioHardware->setVoiceVolume(hwValue);
mHardwareStatus = AUDIO_HW_IDLE;
- // FIXME: This is a temporary fix to re-base the internally
- // generated in-call audio so that it is never muted, which is
- // already the case for the hardware routed in-call audio.
- // When audio stream handling is reworked, this should be
- // addressed more cleanly. Fixes #1324; see discussion at
- // http://review.source.android.com/8224
- mStreamTypes[stream].volume = value * (1.0 - 1.0 / 6.0) + (1.0 / 6.0);
- } else {
- mStreamTypes[stream].volume = value;
+
}
+
+ mHardwareMixerThread->setStreamVolume(stream, value);
+#ifdef WITH_A2DP
+ mA2dpMixerThread->setStreamVolume(stream, value);
+#endif
+
return ret;
}
@@ -826,45 +663,66 @@
return PERMISSION_DENIED;
}
- if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+ if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
return BAD_VALUE;
}
- mStreamTypes[stream].mute = muted;
+
+#ifdef WITH_A2DP
+ mA2dpMixerThread->setStreamMute(stream, muted);
+#endif
+ if (stream == AudioSystem::MUSIC)
+ {
+ AutoMutex lock(&mHardwareLock);
+ if (mForcedRoute != 0)
+ mMusicMuteSaved = muted;
+ else
+ mHardwareMixerThread->setStreamMute(stream, muted);
+ } else {
+ mHardwareMixerThread->setStreamMute(stream, muted);
+ }
+
+
+
return NO_ERROR;
}
float AudioFlinger::streamVolume(int stream) const
{
- if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+ if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
return 0.0f;
}
- if (stream == AudioTrack::VOICE_CALL) {
+ float value = mHardwareMixerThread->streamVolume(stream);
+
+ if (stream == AudioSystem::VOICE_CALL) {
// FIXME: Re-base internally generated in-call audio,
// reverse of above in setStreamVolume.
- return (mStreamTypes[stream].volume - (1.0 / 6.0)) / (1.0 - 1.0 / 6.0);
+ value = (value - 0.01) / 0.99;
}
- return mStreamTypes[stream].volume;
+
+ return value;
}
bool AudioFlinger::streamMute(int stream) const
{
- if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+ if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
return true;
}
- return mStreamTypes[stream].mute;
+
+ if (stream == AudioSystem::MUSIC && mForcedRoute != 0)
+ {
+ return mMusicMuteSaved;
+ }
+ return mHardwareMixerThread->streamMute(stream);
}
bool AudioFlinger::isMusicActive() const
{
- size_t count = mActiveTracks.size();
- for (size_t i = 0 ; i < count ; ++i) {
- sp<Track> t = mActiveTracks[i].promote();
- if (t == 0) continue;
- Track* const track = t.get();
- if (t->mStreamType == AudioTrack::MUSIC)
- return true;
- }
- return false;
+ #ifdef WITH_A2DP
+ if (isA2dpEnabled()) {
+ return mA2dpMixerThread->isMusicActive();
+ }
+ #endif
+ return mHardwareMixerThread->isMusicActive();
}
status_t AudioFlinger::setParameter(const char* key, const char* value)
@@ -872,6 +730,8 @@
status_t result, result2;
AutoMutex lock(mHardwareLock);
mHardwareStatus = AUDIO_SET_PARAMETER;
+
+ LOGV("setParameter() key %s, value %s, tid %d, calling tid %d", key, value, gettid(), IPCThreadState::self()->getCallingPid());
result = mAudioHardware->setParameter(key, value);
if (mA2dpAudioInterface) {
result2 = mA2dpAudioInterface->setParameter(key, value);
@@ -882,15 +742,716 @@
return result;
}
+size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+ return mAudioHardware->getInputBufferSize(sampleRate, format, channelCount);
+}
+
+void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
+{
+
+ LOGV("registerClient() %p, tid %d, calling tid %d", client.get(), gettid(), IPCThreadState::self()->getCallingPid());
+ Mutex::Autolock _l(mLock);
+
+ sp<IBinder> binder = client->asBinder();
+ if (mNotificationClients.indexOf(binder) < 0) {
+ LOGV("Adding notification client %p", binder.get());
+ binder->linkToDeath(this);
+ mNotificationClients.add(binder);
+ client->a2dpEnabledChanged(isA2dpEnabled());
+ }
+}
+
+void AudioFlinger::binderDied(const wp<IBinder>& who) {
+
+ LOGV("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid());
+ Mutex::Autolock _l(mLock);
+
+ IBinder *binder = who.unsafe_get();
+
+ if (binder != NULL) {
+ int index = mNotificationClients.indexOf(binder);
+ if (index >= 0) {
+ LOGV("Removing notification client %p", binder);
+ mNotificationClients.removeAt(index);
+ }
+ }
+}
+
void AudioFlinger::removeClient(pid_t pid)
{
+ LOGV("removeClient() pid %d, tid %d, calling tid %d", pid, gettid(), IPCThreadState::self()->getCallingPid());
Mutex::Autolock _l(mLock);
mClients.removeItem(pid);
}
-status_t AudioFlinger::addTrack(const sp<Track>& track)
+bool AudioFlinger::isA2dpEnabled() const
{
- Mutex::Autolock _l(mLock);
+ return mA2dpEnabled;
+}
+
+void AudioFlinger::handleForcedSpeakerRoute(int command)
+{
+ switch(command) {
+ case ACTIVE_TRACK_ADDED:
+ {
+ AutoMutex lock(mHardwareLock);
+ if (mForcedSpeakerCount++ == 0) {
+ mRouteRestoreTime = 0;
+ mMusicMuteSaved = mHardwareMixerThread->streamMute(AudioSystem::MUSIC);
+ if (mForcedRoute == 0 && !(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
+ LOGV("Route forced to Speaker ON %08x", mSavedRoute | AudioSystem::ROUTE_SPEAKER);
+ mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, true);
+ mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+ mAudioHardware->setMasterVolume(0);
+ usleep(mHardwareMixerThread->latency()*1000);
+ mHardwareStatus = AUDIO_HW_SET_ROUTING;
+ mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute | AudioSystem::ROUTE_SPEAKER);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ // delay track start so that audio hardware has time to siwtch routes
+ usleep(kStartSleepTime);
+ mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+ mAudioHardware->setMasterVolume(mHardwareMixerThread->masterVolume());
+ mHardwareStatus = AUDIO_HW_IDLE;
+ }
+ mForcedRoute = AudioSystem::ROUTE_SPEAKER;
+ }
+ LOGV("mForcedSpeakerCount incremented to %d", mForcedSpeakerCount);
+ }
+ break;
+ case ACTIVE_TRACK_REMOVED:
+ {
+ AutoMutex lock(mHardwareLock);
+ if (mForcedSpeakerCount > 0){
+ if (--mForcedSpeakerCount == 0) {
+ mRouteRestoreTime = systemTime() + milliseconds(kStopSleepTime/1000);
+ }
+ LOGV("mForcedSpeakerCount decremented to %d", mForcedSpeakerCount);
+ } else {
+ LOGE("mForcedSpeakerCount is already zero");
+ }
+ }
+ break;
+ case CHECK_ROUTE_RESTORE_TIME:
+ case FORCE_ROUTE_RESTORE:
+ if (mRouteRestoreTime) {
+ AutoMutex lock(mHardwareLock);
+ if (mRouteRestoreTime &&
+ (systemTime() > mRouteRestoreTime || command == FORCE_ROUTE_RESTORE)) {
+ mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, mMusicMuteSaved);
+ mForcedRoute = 0;
+ if (!(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
+ mHardwareStatus = AUDIO_HW_SET_ROUTING;
+ mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ LOGV("Route forced to Speaker OFF %08x", mSavedRoute);
+ }
+ mRouteRestoreTime = 0;
+ }
+ }
+ break;
+ }
+}
+
+#ifdef WITH_A2DP
+// handleStreamDisablesA2dp_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::handleStreamDisablesA2dp_l(int command)
+{
+ switch(command) {
+ case ACTIVE_TRACK_ADDED:
+ {
+ if (mA2dpDisableCount++ == 0) {
+ if (mA2dpEnabled) {
+ setA2dpEnabled_l(false);
+ mA2dpSuppressed = true;
+ }
+ }
+ LOGV("mA2dpDisableCount incremented to %d", mA2dpDisableCount);
+ }
+ break;
+ case ACTIVE_TRACK_REMOVED:
+ {
+ if (mA2dpDisableCount > 0) {
+ if (--mA2dpDisableCount == 0) {
+ if (mA2dpSuppressed) {
+ setA2dpEnabled_l(true);
+ mA2dpSuppressed = false;
+ }
+ }
+ LOGV("mA2dpDisableCount decremented to %d", mA2dpDisableCount);
+ } else {
+ LOGE("mA2dpDisableCount is already zero");
+ }
+ }
+ break;
+ }
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int outputType)
+ : Thread(false),
+ mAudioFlinger(audioFlinger), mAudioMixer(0), mOutput(output), mOutputType(outputType),
+ mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0), mMixBuffer(0),
+ mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mStandby(false),
+ mInWrite(false)
+{
+ mSampleRate = output->sampleRate();
+ mChannelCount = output->channelCount();
+
+ // FIXME - Current mixer implementation only supports stereo output
+ if (mChannelCount == 1) {
+ LOGE("Invalid audio hardware channel count");
+ }
+
+ mFormat = output->format();
+ mFrameCount = output->bufferSize() / output->channelCount() / sizeof(int16_t);
+ mAudioMixer = new AudioMixer(mFrameCount, output->sampleRate());
+
+ // FIXME - Current mixer implementation only supports stereo output: Always
+ // Allocate a stereo buffer even if HW output is mono.
+ mMixBuffer = new int16_t[mFrameCount * 2];
+ memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t));
+}
+
+AudioFlinger::MixerThread::~MixerThread()
+{
+ delete [] mMixBuffer;
+ delete mAudioMixer;
+}
+
+status_t AudioFlinger::MixerThread::dump(int fd, const Vector<String16>& args)
+{
+ dumpInternals(fd, args);
+ dumpTracks(fd, args);
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::MixerThread::dumpTracks(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "Output %d mixer thread tracks\n", mOutputType);
+ result.append(buffer);
+ result.append(" Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
+ for (size_t i = 0; i < mTracks.size(); ++i) {
+ wp<Track> wTrack = mTracks[i];
+ if (wTrack != 0) {
+ sp<Track> track = wTrack.promote();
+ if (track != 0) {
+ track->dump(buffer, SIZE);
+ result.append(buffer);
+ }
+ }
+ }
+
+ snprintf(buffer, SIZE, "Output %d mixer thread active tracks\n", mOutputType);
+ result.append(buffer);
+ result.append(" Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
+ for (size_t i = 0; i < mActiveTracks.size(); ++i) {
+ wp<Track> wTrack = mTracks[i];
+ if (wTrack != 0) {
+ sp<Track> track = wTrack.promote();
+ if (track != 0) {
+ track->dump(buffer, SIZE);
+ result.append(buffer);
+ }
+ }
+ }
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "Output %d mixer thread internals\n", mOutputType);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", mAudioMixer->trackNames());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
+ result.append(buffer);
+ snprintf(buffer, SIZE, "total writes: %d\n", mNumWrites);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "delayed writes: %d\n", mNumDelayedWrites);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "blocked in write: %d\n", mInWrite);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "standby: %d\n", mStandby);
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+// Thread virtuals
+bool AudioFlinger::MixerThread::threadLoop()
+{
+ unsigned long sleepTime = kBufferRecoveryInUsecs;
+ int16_t* curBuf = mMixBuffer;
+ Vector< sp<Track> > tracksToRemove;
+ size_t enabledTracks = 0;
+ nsecs_t standbyTime = systemTime();
+ size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t);
+ nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
+
+#ifdef WITH_A2DP
+ bool outputTrackActive = false;
+#endif
+
+ do {
+ enabledTracks = 0;
+ { // scope for the AudioFlinger::mLock
+
+ Mutex::Autolock _l(mAudioFlinger->mLock);
+
+#ifdef WITH_A2DP
+ if (mOutputTrack != NULL && !mAudioFlinger->isA2dpEnabled()) {
+ if (outputTrackActive) {
+ mAudioFlinger->mLock.unlock();
+ mOutputTrack->stop();
+ mAudioFlinger->mLock.lock();
+ outputTrackActive = false;
+ }
+ }
+ mAudioFlinger->checkA2dpEnabledChange_l();
+#endif
+
+ const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
+
+ // put audio hardware into standby after short delay
+ if UNLIKELY(!activeTracks.size() && systemTime() > standbyTime) {
+ // wait until we have something to do...
+ LOGV("Audio hardware entering standby, output %d\n", mOutputType);
+ if (!mStandby) {
+ mOutput->standby();
+ mStandby = true;
+ }
+
+#ifdef WITH_A2DP
+ if (outputTrackActive) {
+ mAudioFlinger->mLock.unlock();
+ mOutputTrack->stop();
+ mAudioFlinger->mLock.lock();
+ outputTrackActive = false;
+ }
+#endif
+ if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+ mAudioFlinger->handleForcedSpeakerRoute(FORCE_ROUTE_RESTORE);
+ }
+ // we're about to wait, flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
+ mAudioFlinger->mWaitWorkCV.wait(mAudioFlinger->mLock);
+ LOGV("Audio hardware exiting standby, output %d\n", mOutputType);
+
+ if (mMasterMute == false) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.audio.silent", value, "0");
+ if (atoi(value)) {
+ LOGD("Silence is golden");
+ setMasterMute(true);
+ }
+ }
+
+ standbyTime = systemTime() + kStandbyTimeInNsecs;
+ continue;
+ }
+
+ // Forced route to speaker is handled by hardware mixer thread
+ if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+ mAudioFlinger->handleForcedSpeakerRoute(CHECK_ROUTE_RESTORE_TIME);
+ }
+
+ // find out which tracks need to be processed
+ size_t count = activeTracks.size();
+ for (size_t i=0 ; i<count ; i++) {
+ sp<Track> t = activeTracks[i].promote();
+ if (t == 0) continue;
+
+ Track* const track = t.get();
+ audio_track_cblk_t* cblk = track->cblk();
+
+ // The first time a track is added we wait
+ // for all its buffers to be filled before processing it
+ mAudioMixer->setActiveTrack(track->name());
+ if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
+ !track->isPaused())
+ {
+ //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
+
+ // compute volume for this track
+ int16_t left, right;
+ if (track->isMuted() || mMasterMute || track->isPausing()) {
+ left = right = 0;
+ if (track->isPausing()) {
+ LOGV("paused(%d)", track->name());
+ track->setPaused();
+ }
+ } else {
+ float typeVolume = mStreamTypes[track->type()].volume;
+ float v = mMasterVolume * typeVolume;
+ float v_clamped = v * cblk->volume[0];
+ if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+ left = int16_t(v_clamped);
+ v_clamped = v * cblk->volume[1];
+ if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+ right = int16_t(v_clamped);
+ }
+
+ // XXX: these things DON'T need to be done each time
+ mAudioMixer->setBufferProvider(track);
+ mAudioMixer->enable(AudioMixer::MIXING);
+
+ int param;
+ if ( track->mFillingUpStatus == Track::FS_FILLED) {
+ // no ramp for the first volume setting
+ track->mFillingUpStatus = Track::FS_ACTIVE;
+ if (track->mState == TrackBase::RESUMING) {
+ track->mState = TrackBase::ACTIVE;
+ param = AudioMixer::RAMP_VOLUME;
+ } else {
+ param = AudioMixer::VOLUME;
+ }
+ } else {
+ param = AudioMixer::RAMP_VOLUME;
+ }
+ mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left);
+ mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right);
+ mAudioMixer->setParameter(
+ AudioMixer::TRACK,
+ AudioMixer::FORMAT, track->format());
+ mAudioMixer->setParameter(
+ AudioMixer::TRACK,
+ AudioMixer::CHANNEL_COUNT, track->channelCount());
+ mAudioMixer->setParameter(
+ AudioMixer::RESAMPLE,
+ AudioMixer::SAMPLE_RATE,
+ int(cblk->sampleRate));
+
+ // reset retry count
+ track->mRetryCount = kMaxTrackRetries;
+ enabledTracks++;
+ } else {
+ //LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
+ if (track->isStopped()) {
+ track->reset();
+ }
+ if (track->isTerminated() || track->isStopped() || track->isPaused()) {
+ // We have consumed all the buffers of this track.
+ // Remove it from the list of active tracks.
+ LOGV("remove(%d) from active list", track->name());
+ tracksToRemove.add(track);
+ } else {
+ // No buffers for this track. Give it a few chances to
+ // fill a buffer, then remove it from active list.
+ if (--(track->mRetryCount) <= 0) {
+ LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
+ tracksToRemove.add(track);
+ }
+ }
+ // LOGV("disable(%d)", track->name());
+ mAudioMixer->disable(AudioMixer::MIXING);
+ }
+ }
+
+ // remove all the tracks that need to be...
+ count = tracksToRemove.size();
+ if (UNLIKELY(count)) {
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<Track>& track = tracksToRemove[i];
+ removeActiveTrack_l(track);
+ if (track->isTerminated()) {
+ mTracks.remove(track);
+ deleteTrackName_l(track->mName);
+ }
+ }
+ }
+ }
+
+ if (LIKELY(enabledTracks)) {
+ // mix buffers...
+ mAudioMixer->process(curBuf);
+
+#ifdef WITH_A2DP
+ if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) {
+ if (!outputTrackActive) {
+ LOGV("starting output track in mixer for output %d", mOutputType);
+ mOutputTrack->start();
+ outputTrackActive = true;
+ }
+ mOutputTrack->write(curBuf, mFrameCount);
+ }
+#endif
+
+ // output audio to hardware
+ mLastWriteTime = systemTime();
+ mInWrite = true;
+ mOutput->write(curBuf, mixBufferSize);
+ mNumWrites++;
+ mInWrite = false;
+ mStandby = false;
+ nsecs_t temp = systemTime();
+ standbyTime = temp + kStandbyTimeInNsecs;
+ nsecs_t delta = temp - mLastWriteTime;
+ if (delta > maxPeriod) {
+ LOGW("write blocked for %llu msecs", ns2ms(delta));
+ mNumDelayedWrites++;
+ }
+ sleepTime = kBufferRecoveryInUsecs;
+ } else {
+#ifdef WITH_A2DP
+ if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) {
+ if (outputTrackActive) {
+ mOutputTrack->write(curBuf, 0);
+ if (mOutputTrack->bufferQueueEmpty()) {
+ mOutputTrack->stop();
+ outputTrackActive = false;
+ } else {
+ standbyTime = systemTime() + kStandbyTimeInNsecs;
+ }
+ }
+ }
+#endif
+ // There was nothing to mix this round, which means all
+ // active tracks were late. Sleep a little bit to give
+ // them another chance. If we're too late, the audio
+ // hardware will zero-fill for us.
+ //LOGV("no buffers - usleep(%lu)", sleepTime);
+ usleep(sleepTime);
+ if (sleepTime < kMaxBufferRecoveryInUsecs) {
+ sleepTime += kBufferRecoveryInUsecs;
+ }
+ }
+
+ // finally let go of all our tracks, without the lock held
+ // since we can't guarantee the destructors won't acquire that
+ // same lock.
+ tracksToRemove.clear();
+ } while (true);
+
+ return false;
+}
+
+status_t AudioFlinger::MixerThread::readyToRun()
+{
+ if (mSampleRate == 0) {
+ LOGE("No working audio driver found.");
+ return NO_INIT;
+ }
+ LOGI("AudioFlinger's thread ready to run for output %d", mOutputType);
+ return NO_ERROR;
+}
+
+void AudioFlinger::MixerThread::onFirstRef()
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "Mixer Thread for output %d", mOutputType);
+
+ run(buffer, ANDROID_PRIORITY_URGENT_AUDIO);
+}
+
+// MixerThread::createTrack_l() must be called with AudioFlinger::mLock held
+sp<AudioFlinger::MixerThread::Track> AudioFlinger::MixerThread::createTrack_l(
+ const sp<AudioFlinger::Client>& client,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount,
+ const sp<IMemory>& sharedBuffer,
+ status_t *status)
+{
+ sp<Track> track;
+ status_t lStatus;
+
+ // Resampler implementation limits input sampling rate to 2 x output sampling rate.
+ if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) {
+ LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate);
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+
+
+ if (mSampleRate == 0) {
+ LOGE("Audio driver not initialized.");
+ lStatus = NO_INIT;
+ goto Exit;
+ }
+
+ track = new Track(this, client, streamType, sampleRate, format,
+ channelCount, frameCount, sharedBuffer);
+ if (track->getCblk() == NULL) {
+ lStatus = NO_MEMORY;
+ goto Exit;
+ }
+ mTracks.add(track);
+ lStatus = NO_ERROR;
+
+Exit:
+ if(status) {
+ *status = lStatus;
+ }
+ return track;
+}
+
+// getTracks_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::getTracks_l(
+ SortedVector < sp<Track> >& tracks,
+ SortedVector < wp<Track> >& activeTracks)
+{
+ size_t size = mTracks.size();
+ LOGV ("MixerThread::getTracks_l() for output %d, mTracks.size %d, mActiveTracks.size %d", mOutputType, mTracks.size(), mActiveTracks.size());
+ for (size_t i = 0; i < size; i++) {
+ sp<Track> t = mTracks[i];
+ if (AudioSystem::routedToA2dpOutput(t->mStreamType)) {
+ tracks.add(t);
+ int j = mActiveTracks.indexOf(t);
+ if (j >= 0) {
+ t = mActiveTracks[j].promote();
+ if (t != NULL) {
+ activeTracks.add(t);
+ }
+ }
+ }
+ }
+
+ size = activeTracks.size();
+ for (size_t i = 0; i < size; i++) {
+ removeActiveTrack_l(activeTracks[i]);
+ }
+
+ size = tracks.size();
+ for (size_t i = 0; i < size; i++) {
+ sp<Track> t = tracks[i];
+ mTracks.remove(t);
+ deleteTrackName_l(t->name());
+ }
+}
+
+// putTracks_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::putTracks_l(
+ SortedVector < sp<Track> >& tracks,
+ SortedVector < wp<Track> >& activeTracks)
+{
+
+ LOGV ("MixerThread::putTracks_l() for output %d, tracks.size %d, activeTracks.size %d", mOutputType, tracks.size(), activeTracks.size());
+
+ size_t size = tracks.size();
+ for (size_t i = 0; i < size ; i++) {
+ sp<Track> t = tracks[i];
+ int name = getTrackName_l();
+
+ if (name < 0) return;
+
+ t->mName = name;
+ t->mMixerThread = this;
+ mTracks.add(t);
+
+ int j = activeTracks.indexOf(t);
+ if (j >= 0) {
+ addActiveTrack_l(t);
+ }
+ }
+}
+
+uint32_t AudioFlinger::MixerThread::sampleRate() const
+{
+ return mSampleRate;
+}
+
+int AudioFlinger::MixerThread::channelCount() const
+{
+ return mChannelCount;
+}
+
+int AudioFlinger::MixerThread::format() const
+{
+ return mFormat;
+}
+
+size_t AudioFlinger::MixerThread::frameCount() const
+{
+ return mFrameCount;
+}
+
+uint32_t AudioFlinger::MixerThread::latency() const
+{
+ if (mOutput) {
+ return mOutput->latency();
+ }
+ else {
+ return 0;
+ }
+}
+
+status_t AudioFlinger::MixerThread::setMasterVolume(float value)
+{
+ mMasterVolume = value;
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::MixerThread::setMasterMute(bool muted)
+{
+ mMasterMute = muted;
+ return NO_ERROR;
+}
+
+float AudioFlinger::MixerThread::masterVolume() const
+{
+ return mMasterVolume;
+}
+
+bool AudioFlinger::MixerThread::masterMute() const
+{
+ return mMasterMute;
+}
+
+status_t AudioFlinger::MixerThread::setStreamVolume(int stream, float value)
+{
+ mStreamTypes[stream].volume = value;
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::MixerThread::setStreamMute(int stream, bool muted)
+{
+ mStreamTypes[stream].mute = muted;
+ return NO_ERROR;
+}
+
+float AudioFlinger::MixerThread::streamVolume(int stream) const
+{
+ return mStreamTypes[stream].volume;
+}
+
+bool AudioFlinger::MixerThread::streamMute(int stream) const
+{
+ return mStreamTypes[stream].mute;
+}
+
+bool AudioFlinger::MixerThread::isMusicActive() const
+{
+ size_t count = mActiveTracks.size();
+ for (size_t i = 0 ; i < count ; ++i) {
+ sp<Track> t = mActiveTracks[i].promote();
+ if (t == 0) continue;
+ Track* const track = t.get();
+ if (t->mStreamType == AudioSystem::MUSIC)
+ return true;
+ }
+ return false;
+}
+
+// addTrack_l() must be called with AudioFlinger::mLock held
+status_t AudioFlinger::MixerThread::addTrack_l(const sp<Track>& track)
+{
+ status_t status = ALREADY_EXISTS;
// here the track could be either new, or restarted
// in both cases "unstop" the track
@@ -903,139 +1464,135 @@
}
// set retry count for buffer fill
track->mRetryCount = kMaxTrackStartupRetries;
- LOGV("mWaitWorkCV.broadcast");
- mWaitWorkCV.broadcast();
-
if (mActiveTracks.indexOf(track) < 0) {
// the track is newly added, make sure it fills up all its
// buffers before playing. This is to ensure the client will
// effectively get the latency it requested.
track->mFillingUpStatus = Track::FS_FILLING;
track->mResetDone = false;
- addActiveTrack(track);
- return NO_ERROR;
+ addActiveTrack_l(track);
+ status = NO_ERROR;
}
- return ALREADY_EXISTS;
+
+ LOGV("mWaitWorkCV.broadcast");
+ mAudioFlinger->mWaitWorkCV.broadcast();
+
+ return status;
}
-void AudioFlinger::removeTrack(wp<Track> track, int name)
+// removeTrack_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::removeTrack_l(wp<Track> track, int name)
{
- Mutex::Autolock _l(mLock);
sp<Track> t = track.promote();
if (t!=NULL && (t->mState <= TrackBase::STOPPED)) {
- remove_track_l(track, name);
- }
-}
-
-void AudioFlinger::remove_track_l(wp<Track> track, int name)
-{
- sp<Track> t = track.promote();
- if (t!=NULL) {
t->reset();
+ deleteTrackName_l(name);
+ removeActiveTrack_l(track);
+ mAudioFlinger->mWaitWorkCV.broadcast();
}
- audioMixer()->deleteTrackName(name);
- removeActiveTrack(track);
- mWaitWorkCV.broadcast();
}
-void AudioFlinger::destroyTrack(const sp<Track>& track)
+// destroyTrack_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::destroyTrack_l(const sp<Track>& track)
{
- // NOTE: We're acquiring a strong reference on the track before
- // acquiring the lock, this is to make sure removing it from
- // mTracks won't cause the destructor to be called while the lock is
- // held (note that technically, 'track' could be a reference to an item
- // in mTracks, which is why we need to do this).
- sp<Track> keep(track);
- Mutex::Autolock _l(mLock);
track->mState = TrackBase::TERMINATED;
if (mActiveTracks.indexOf(track) < 0) {
LOGV("remove track (%d) and delete from mixer", track->name());
mTracks.remove(track);
- audioMixer()->deleteTrackName(keep->name());
+ deleteTrackName_l(track->name());
}
}
-void AudioFlinger::addActiveTrack(const wp<Track>& t)
+// addActiveTrack_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::addActiveTrack_l(const wp<Track>& t)
{
mActiveTracks.add(t);
+ // Force routing to speaker for certain stream types
+ // The forced routing to speaker is managed by hardware mixer
+ if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+ sp<Track> track = t.promote();
+ if (track == NULL) return;
+
+ if (streamForcedToSpeaker(track->type())) {
+ mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_ADDED);
+ }
#ifdef WITH_A2DP
- // disable A2DP for certain stream types
- sp<Track> track = t.promote();
- if (streamDisablesA2dp(track->type())) {
- if (mA2dpDisableCount++ == 0 && isA2dpEnabled()) {
- setA2dpEnabled(false);
- mA2dpSuppressed = true;
- LOGD("mA2dpSuppressed = true\n");
+ // AudioFlinger::mLock must be locked before calling
+ // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l().
+ if (streamDisablesA2dp(track->type())) {
+ mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_ADDED);
}
- LOGD("mA2dpDisableCount incremented to %d\n", mA2dpDisableCount);
- }
#endif
+ }
}
-void AudioFlinger::removeActiveTrack(const wp<Track>& t)
+// removeActiveTrack_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::removeActiveTrack_l(const wp<Track>& t)
{
mActiveTracks.remove(t);
+
+ // Force routing to speaker for certain stream types
+ // The forced routing to speaker is managed by hardware mixer
+ if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+ sp<Track> track = t.promote();
+ if (track == NULL) return;
+
+ if (streamForcedToSpeaker(track->type())) {
+ mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_REMOVED);
+ }
#ifdef WITH_A2DP
- // disable A2DP for certain stream types
- sp<Track> track = t.promote();
- if (streamDisablesA2dp(track->type())) {
- if (mA2dpDisableCount > 0) {
- mA2dpDisableCount--;
- if (mA2dpDisableCount == 0 && mA2dpSuppressed) {
- setA2dpEnabled(true);
- mA2dpSuppressed = false;
- }
- LOGD("mA2dpDisableCount decremented to %d\n", mA2dpDisableCount);
- } else
- LOGE("mA2dpDisableCount is already zero");
- }
+ // AudioFlinger::mLock must be locked before calling
+ // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l().
+ if (streamDisablesA2dp(track->type())) {
+ mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_REMOVED);
+ }
#endif
+ }
+}
+
+// getTrackName_l() must be called with AudioFlinger::mLock held
+int AudioFlinger::MixerThread::getTrackName_l()
+{
+ return mAudioMixer->getTrackName();
+}
+
+// deleteTrackName_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::deleteTrackName_l(int name)
+{
+ mAudioMixer->deleteTrackName(name);
+}
+
+size_t AudioFlinger::MixerThread::getOutputFrameCount()
+{
+ return mOutput->bufferSize() / mOutput->channelCount() / sizeof(int16_t);
}
// ----------------------------------------------------------------------------
-AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
- : RefBase(),
- mAudioFlinger(audioFlinger),
- mMemoryDealer(new MemoryDealer(1024*1024)),
- mPid(pid)
-{
- // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
-}
-
-AudioFlinger::Client::~Client()
-{
- mAudioFlinger->removeClient(mPid);
-}
-
-const sp<MemoryDealer>& AudioFlinger::Client::heap() const
-{
- return mMemoryDealer;
-}
-
-// ----------------------------------------------------------------------------
-
-AudioFlinger::TrackBase::TrackBase(
- const sp<AudioFlinger>& audioFlinger,
+// TrackBase constructor must be called with AudioFlinger::mLock held
+AudioFlinger::MixerThread::TrackBase::TrackBase(
+ const sp<MixerThread>& mixerThread,
const sp<Client>& client,
int streamType,
uint32_t sampleRate,
int format,
int channelCount,
int frameCount,
+ uint32_t flags,
const sp<IMemory>& sharedBuffer)
: RefBase(),
- mAudioFlinger(audioFlinger),
+ mMixerThread(mixerThread),
mClient(client),
mStreamType(streamType),
mFrameCount(0),
mState(IDLE),
mClientTid(-1),
mFormat(format),
- mFlags(0)
+ mFlags(flags & ~SYSTEM_FLAGS_MASK)
{
- mName = audioFlinger->audioMixer()->getTrackName();
+ mName = mixerThread->getTrackName_l();
+ LOGV("TrackBase contructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid());
if (mName < 0) {
LOGE("no more track names availlable");
return;
@@ -1043,7 +1600,6 @@
LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
-
// LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
size_t size = sizeof(audio_track_cblk_t);
size_t bufferSize = frameCount*channelCount*sizeof(int16_t);
@@ -1051,41 +1607,60 @@
size += bufferSize;
}
- mCblkMemory = client->heap()->allocate(size);
- if (mCblkMemory != 0) {
- mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer());
- if (mCblk) { // construct the shared structure in-place.
- new(mCblk) audio_track_cblk_t();
- // clear all buffers
- mCblk->frameCount = frameCount;
- mCblk->sampleRate = sampleRate;
- mCblk->channels = channelCount;
- if (sharedBuffer == 0) {
- mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
- memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
- // Force underrun condition to avoid false underrun callback until first data is
- // written to buffer
- mCblk->flowControlFlag = 1;
- } else {
- mBuffer = sharedBuffer->pointer();
+ if (client != NULL) {
+ mCblkMemory = client->heap()->allocate(size);
+ if (mCblkMemory != 0) {
+ mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer());
+ if (mCblk) { // construct the shared structure in-place.
+ new(mCblk) audio_track_cblk_t();
+ // clear all buffers
+ mCblk->frameCount = frameCount;
+ mCblk->sampleRate = sampleRate;
+ mCblk->channels = channelCount;
+ if (sharedBuffer == 0) {
+ mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
+ memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
+ // Force underrun condition to avoid false underrun callback until first data is
+ // written to buffer
+ mCblk->flowControlFlag = 1;
+ } else {
+ mBuffer = sharedBuffer->pointer();
+ }
+ mBufferEnd = (uint8_t *)mBuffer + bufferSize;
}
- mBufferEnd = (uint8_t *)mBuffer + bufferSize;
+ } else {
+ LOGE("not enough memory for AudioTrack size=%u", size);
+ client->heap()->dump("AudioTrack");
+ return;
}
- } else {
- LOGE("not enough memory for AudioTrack size=%u", size);
- client->heap()->dump("AudioTrack");
- return;
- }
+ } else {
+ mCblk = (audio_track_cblk_t *)(new uint8_t[size]);
+ if (mCblk) { // construct the shared structure in-place.
+ new(mCblk) audio_track_cblk_t();
+ // clear all buffers
+ mCblk->frameCount = frameCount;
+ mCblk->sampleRate = sampleRate;
+ mCblk->channels = channelCount;
+ mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
+ memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
+ // Force underrun condition to avoid false underrun callback until first data is
+ // written to buffer
+ mCblk->flowControlFlag = 1;
+ mBufferEnd = (uint8_t *)mBuffer + bufferSize;
+ }
+ }
}
-AudioFlinger::TrackBase::~TrackBase()
+AudioFlinger::MixerThread::TrackBase::~TrackBase()
{
- mCblk->~audio_track_cblk_t(); // destroy our shared-structure.
+ if (mCblk) {
+ mCblk->~audio_track_cblk_t(); // destroy our shared-structure.
+ }
mCblkMemory.clear(); // and free the shared memory
mClient.clear();
}
-void AudioFlinger::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
+void AudioFlinger::MixerThread::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
{
buffer->raw = 0;
mFrameCount = buffer->frameCount;
@@ -1093,7 +1668,7 @@
buffer->frameCount = 0;
}
-bool AudioFlinger::TrackBase::step() {
+bool AudioFlinger::MixerThread::TrackBase::step() {
bool result;
audio_track_cblk_t* cblk = this->cblk();
@@ -1105,31 +1680,31 @@
return result;
}
-void AudioFlinger::TrackBase::reset() {
+void AudioFlinger::MixerThread::TrackBase::reset() {
audio_track_cblk_t* cblk = this->cblk();
cblk->user = 0;
cblk->server = 0;
cblk->userBase = 0;
cblk->serverBase = 0;
- mFlags = 0;
+ mFlags &= (uint32_t)(~SYSTEM_FLAGS_MASK);
LOGV("TrackBase::reset");
}
-sp<IMemory> AudioFlinger::TrackBase::getCblk() const
+sp<IMemory> AudioFlinger::MixerThread::TrackBase::getCblk() const
{
return mCblkMemory;
}
-int AudioFlinger::TrackBase::sampleRate() const {
+int AudioFlinger::MixerThread::TrackBase::sampleRate() const {
return mCblk->sampleRate;
}
-int AudioFlinger::TrackBase::channelCount() const {
+int AudioFlinger::MixerThread::TrackBase::channelCount() const {
return mCblk->channels;
}
-void* AudioFlinger::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
+void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
audio_track_cblk_t* cblk = this->cblk();
int16_t *bufferStart = (int16_t *)mBuffer + (offset-cblk->serverBase)*cblk->channels;
int16_t *bufferEnd = bufferStart + frames * cblk->channels;
@@ -1148,8 +1723,9 @@
// ----------------------------------------------------------------------------
-AudioFlinger::Track::Track(
- const sp<AudioFlinger>& audioFlinger,
+// Track constructor must be called with AudioFlinger::mLock held
+AudioFlinger::MixerThread::Track::Track(
+ const sp<MixerThread>& mixerThread,
const sp<Client>& client,
int streamType,
uint32_t sampleRate,
@@ -1157,7 +1733,7 @@
int channelCount,
int frameCount,
const sp<IMemory>& sharedBuffer)
- : TrackBase(audioFlinger, client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer)
+ : TrackBase(mixerThread, client, streamType, sampleRate, format, channelCount, frameCount, 0, sharedBuffer)
{
mVolume[0] = 1.0f;
mVolume[1] = 1.0f;
@@ -1165,23 +1741,36 @@
mSharedBuffer = sharedBuffer;
}
-AudioFlinger::Track::~Track()
+AudioFlinger::MixerThread::Track::~Track()
{
wp<Track> weak(this); // never create a strong ref from the dtor
+ Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
mState = TERMINATED;
- mAudioFlinger->removeTrack(weak, mName);
+ mMixerThread->removeTrack_l(weak, mName);
}
-void AudioFlinger::Track::destroy()
+void AudioFlinger::MixerThread::Track::destroy()
{
- mAudioFlinger->destroyTrack(this);
+ // NOTE: destroyTrack_l() can remove a strong reference to this Track
+ // by removing it from mTracks vector, so there is a risk that this Tracks's
+ // desctructor is called. As the destructor needs to lock AudioFlinger::mLock,
+ // we must acquire a strong reference on this Track before locking AudioFlinger::mLock
+ // here so that the destructor is called only when exiting this function.
+ // On the other hand, as long as Track::destroy() is only called by
+ // TrackHandle destructor, the TrackHandle still holds a strong ref on
+ // this Track with its member mTrack.
+ sp<Track> keep(this);
+ { // scope for AudioFlinger::mLock
+ Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
+ mMixerThread->destroyTrack_l(this);
+ }
}
-void AudioFlinger::Track::dump(char* buffer, size_t size)
+void AudioFlinger::MixerThread::Track::dump(char* buffer, size_t size)
{
snprintf(buffer, size, " %5d %5d %3u %3u %3u %3u %1d %1d %1d %5u %5u %5u %04x %04x\n",
mName - AudioMixer::TRACK0,
- mClient->pid(),
+ (mClient == NULL) ? getpid() : mClient->pid(),
mStreamType,
mFormat,
mCblk->channels,
@@ -1196,7 +1785,7 @@
mCblk->user);
}
-status_t AudioFlinger::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+status_t AudioFlinger::MixerThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
{
audio_track_cblk_t* cblk = this->cblk();
uint32_t framesReady;
@@ -1236,53 +1825,55 @@
return NOT_ENOUGH_DATA;
}
-bool AudioFlinger::Track::isReady() const {
+bool AudioFlinger::MixerThread::Track::isReady() const {
if (mFillingUpStatus != FS_FILLING) return true;
if (mCblk->framesReady() >= mCblk->frameCount ||
mCblk->forceReady) {
mFillingUpStatus = FS_FILLED;
mCblk->forceReady = 0;
+ LOGV("Track::isReady() track %d for output %d", mName, mMixerThread->mOutputType);
return true;
}
return false;
}
-status_t AudioFlinger::Track::start()
+status_t AudioFlinger::MixerThread::Track::start()
{
- LOGV("start(%d)", mName);
- mAudioFlinger->addTrack(this);
+ LOGV("start(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType);
+ Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
+ mMixerThread->addTrack_l(this);
return NO_ERROR;
}
-void AudioFlinger::Track::stop()
+void AudioFlinger::MixerThread::Track::stop()
{
- LOGV("stop(%d)", mName);
- Mutex::Autolock _l(mAudioFlinger->mLock);
+ LOGV("stop(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType);
+ Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
if (mState > STOPPED) {
mState = STOPPED;
// If the track is not active (PAUSED and buffers full), flush buffers
- if (mAudioFlinger->mActiveTracks.indexOf(this) < 0) {
+ if (mMixerThread->mActiveTracks.indexOf(this) < 0) {
reset();
}
LOGV("(> STOPPED) => STOPPED (%d)", mName);
}
}
-void AudioFlinger::Track::pause()
+void AudioFlinger::MixerThread::Track::pause()
{
- LOGV("pause(%d)", mName);
- Mutex::Autolock _l(mAudioFlinger->mLock);
+ LOGV("pause(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+ Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
if (mState == ACTIVE || mState == RESUMING) {
mState = PAUSING;
LOGV("ACTIVE/RESUMING => PAUSING (%d)", mName);
}
}
-void AudioFlinger::Track::flush()
+void AudioFlinger::MixerThread::Track::flush()
{
LOGV("flush(%d)", mName);
- Mutex::Autolock _l(mAudioFlinger->mLock);
+ Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
if (mState != STOPPED && mState != PAUSED && mState != PAUSING) {
return;
}
@@ -1298,7 +1889,7 @@
reset();
}
-void AudioFlinger::Track::reset()
+void AudioFlinger::MixerThread::Track::reset()
{
// Do not reset twice to avoid discarding data written just after a flush and before
// the audioflinger thread detects the track is stopped.
@@ -1313,12 +1904,12 @@
}
}
-void AudioFlinger::Track::mute(bool muted)
+void AudioFlinger::MixerThread::Track::mute(bool muted)
{
mMute = muted;
}
-void AudioFlinger::Track::setVolume(float left, float right)
+void AudioFlinger::MixerThread::Track::setVolume(float left, float right)
{
mVolume[0] = left;
mVolume[1] = right;
@@ -1326,7 +1917,292 @@
// ----------------------------------------------------------------------------
-AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::Track>& track)
+// RecordTrack constructor must be called with AudioFlinger::mLock held
+AudioFlinger::MixerThread::RecordTrack::RecordTrack(
+ const sp<MixerThread>& mixerThread,
+ const sp<Client>& client,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount,
+ uint32_t flags)
+ : TrackBase(mixerThread, client, streamType, sampleRate, format,
+ channelCount, frameCount, flags, 0),
+ mOverflow(false)
+{
+}
+
+AudioFlinger::MixerThread::RecordTrack::~RecordTrack()
+{
+ Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
+ mMixerThread->deleteTrackName_l(mName);
+}
+
+status_t AudioFlinger::MixerThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+{
+ audio_track_cblk_t* cblk = this->cblk();
+ uint32_t framesAvail;
+ uint32_t framesReq = buffer->frameCount;
+
+ // Check if last stepServer failed, try to step now
+ if (mFlags & TrackBase::STEPSERVER_FAILED) {
+ if (!step()) goto getNextBuffer_exit;
+ LOGV("stepServer recovered");
+ mFlags &= ~TrackBase::STEPSERVER_FAILED;
+ }
+
+ framesAvail = cblk->framesAvailable_l();
+
+ if (LIKELY(framesAvail)) {
+ uint32_t s = cblk->server;
+ uint32_t bufferEnd = cblk->serverBase + cblk->frameCount;
+
+ if (framesReq > framesAvail) {
+ framesReq = framesAvail;
+ }
+ if (s + framesReq > bufferEnd) {
+ framesReq = bufferEnd - s;
+ }
+
+ buffer->raw = getBuffer(s, framesReq);
+ if (buffer->raw == 0) goto getNextBuffer_exit;
+
+ buffer->frameCount = framesReq;
+ return NO_ERROR;
+ }
+
+getNextBuffer_exit:
+ buffer->raw = 0;
+ buffer->frameCount = 0;
+ return NOT_ENOUGH_DATA;
+}
+
+status_t AudioFlinger::MixerThread::RecordTrack::start()
+{
+ return mMixerThread->mAudioFlinger->startRecord(this);
+}
+
+void AudioFlinger::MixerThread::RecordTrack::stop()
+{
+ mMixerThread->mAudioFlinger->stopRecord(this);
+ TrackBase::reset();
+ // Force overerrun condition to avoid false overrun callback until first data is
+ // read from buffer
+ mCblk->flowControlFlag = 1;
+}
+
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::MixerThread::OutputTrack::OutputTrack(
+ const sp<MixerThread>& mixerThread,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount)
+ : Track(mixerThread, NULL, AudioSystem::SYSTEM, sampleRate, format, channelCount, frameCount, NULL),
+ mOutputMixerThread(mixerThread)
+{
+
+ mCblk->out = 1;
+ mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+ mCblk->volume[0] = mCblk->volume[1] = 0x1000;
+ mOutBuffer.frameCount = 0;
+ mCblk->bufferTimeoutMs = 10;
+
+ LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p",
+ mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd);
+
+}
+
+AudioFlinger::MixerThread::OutputTrack::~OutputTrack()
+{
+ stop();
+}
+
+status_t AudioFlinger::MixerThread::OutputTrack::start()
+{
+ status_t status = Track::start();
+
+ mRetryCount = 127;
+ return status;
+}
+
+void AudioFlinger::MixerThread::OutputTrack::stop()
+{
+ Track::stop();
+ clearBufferQueue();
+ mOutBuffer.frameCount = 0;
+}
+
+void AudioFlinger::MixerThread::OutputTrack::write(int16_t* data, uint32_t frames)
+{
+ Buffer *pInBuffer;
+ Buffer inBuffer;
+ uint32_t channels = mCblk->channels;
+
+ inBuffer.frameCount = frames;
+ inBuffer.i16 = data;
+
+ if (mCblk->user == 0) {
+ if (mOutputMixerThread->isMusicActive()) {
+ mCblk->forceReady = 1;
+ LOGV("OutputTrack::start() force ready");
+ } else if (mCblk->frameCount > frames){
+ if (mBufferQueue.size() < kMaxOutputTrackBuffers) {
+ uint32_t startFrames = (mCblk->frameCount - frames);
+ LOGV("OutputTrack::start() write %d frames", startFrames);
+ pInBuffer = new Buffer;
+ pInBuffer->mBuffer = new int16_t[startFrames * channels];
+ pInBuffer->frameCount = startFrames;
+ pInBuffer->i16 = pInBuffer->mBuffer;
+ memset(pInBuffer->raw, 0, startFrames * channels * sizeof(int16_t));
+ mBufferQueue.add(pInBuffer);
+ } else {
+ LOGW ("OutputTrack::write() no more buffers");
+ }
+ }
+ }
+
+ while (1) {
+ // First write pending buffers, then new data
+ if (mBufferQueue.size()) {
+ pInBuffer = mBufferQueue.itemAt(0);
+ } else {
+ pInBuffer = &inBuffer;
+ }
+
+ if (pInBuffer->frameCount == 0) {
+ break;
+ }
+
+ if (mOutBuffer.frameCount == 0) {
+ mOutBuffer.frameCount = pInBuffer->frameCount;
+ if (obtainBuffer(&mOutBuffer) == (status_t)AudioTrack::NO_MORE_BUFFERS) {
+ break;
+ }
+ }
+
+ uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount : pInBuffer->frameCount;
+ memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channels * sizeof(int16_t));
+ mCblk->stepUser(outFrames);
+ pInBuffer->frameCount -= outFrames;
+ pInBuffer->i16 += outFrames * channels;
+ mOutBuffer.frameCount -= outFrames;
+ mOutBuffer.i16 += outFrames * channels;
+
+ if (pInBuffer->frameCount == 0) {
+ if (mBufferQueue.size()) {
+ mBufferQueue.removeAt(0);
+ delete [] pInBuffer->mBuffer;
+ delete pInBuffer;
+ } else {
+ break;
+ }
+ }
+ }
+
+ // If we could not write all frames, allocate a buffer and queue it for next time.
+ if (inBuffer.frameCount) {
+ if (mBufferQueue.size() < kMaxOutputTrackBuffers) {
+ pInBuffer = new Buffer;
+ pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channels];
+ pInBuffer->frameCount = inBuffer.frameCount;
+ pInBuffer->i16 = pInBuffer->mBuffer;
+ memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channels * sizeof(int16_t));
+ mBufferQueue.add(pInBuffer);
+ } else {
+ LOGW("OutputTrack::write() no more buffers");
+ }
+ }
+
+ // Calling write() with a 0 length buffer, means that no more data will be written:
+ // If no more buffers are pending, fill output track buffer to make sure it is started
+ // by output mixer.
+ if (frames == 0 && mBufferQueue.size() == 0 && mCblk->user < mCblk->frameCount) {
+ frames = mCblk->frameCount - mCblk->user;
+ pInBuffer = new Buffer;
+ pInBuffer->mBuffer = new int16_t[frames * channels];
+ pInBuffer->frameCount = frames;
+ pInBuffer->i16 = pInBuffer->mBuffer;
+ memset(pInBuffer->raw, 0, frames * channels * sizeof(int16_t));
+ mBufferQueue.add(pInBuffer);
+ }
+
+}
+
+status_t AudioFlinger::MixerThread::OutputTrack::obtainBuffer(AudioBufferProvider::Buffer* buffer)
+{
+ int active;
+ int timeout = 0;
+ status_t result;
+ audio_track_cblk_t* cblk = mCblk;
+ uint32_t framesReq = buffer->frameCount;
+
+ LOGV("OutputTrack::obtainBuffer user %d, server %d", cblk->user, cblk->server);
+ buffer->frameCount = 0;
+
+ uint32_t framesAvail = cblk->framesAvailable();
+
+ if (framesAvail == 0) {
+ return AudioTrack::NO_MORE_BUFFERS;
+ }
+
+ if (framesReq > framesAvail) {
+ framesReq = framesAvail;
+ }
+
+ uint32_t u = cblk->user;
+ uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
+
+ if (u + framesReq > bufferEnd) {
+ framesReq = bufferEnd - u;
+ }
+
+ buffer->frameCount = framesReq;
+ buffer->raw = (void *)cblk->buffer(u);
+ return NO_ERROR;
+}
+
+
+void AudioFlinger::MixerThread::OutputTrack::clearBufferQueue()
+{
+ size_t size = mBufferQueue.size();
+ Buffer *pBuffer;
+
+ for (size_t i = 0; i < size; i++) {
+ pBuffer = mBufferQueue.itemAt(i);
+ delete [] pBuffer->mBuffer;
+ delete pBuffer;
+ }
+ mBufferQueue.clear();
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
+ : RefBase(),
+ mAudioFlinger(audioFlinger),
+ mMemoryDealer(new MemoryDealer(1024*1024)),
+ mPid(pid)
+{
+ // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
+}
+
+AudioFlinger::Client::~Client()
+{
+ mAudioFlinger->removeClient(mPid);
+}
+
+const sp<MemoryDealer>& AudioFlinger::Client::heap() const
+{
+ return mMemoryDealer;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::MixerThread::Track>& track)
: BnAudioTrack(),
mTrack(track)
{
@@ -1386,8 +2262,7 @@
uint32_t flags,
status_t *status)
{
- sp<AudioRecordThread> thread;
- sp<RecordTrack> recordTrack;
+ sp<MixerThread::RecordTrack> recordTrack;
sp<RecordHandle> recordHandle;
sp<Client> client;
wp<Client> wclient;
@@ -1414,12 +2289,6 @@
goto Exit;
}
- if (mSampleRate == 0) {
- LOGE("Audio driver not initialized");
- lStatus = NO_INIT;
- goto Exit;
- }
-
if (mAudioRecordThread == 0) {
LOGE("Audio record thread not started");
lStatus = NO_INIT;
@@ -1436,7 +2305,7 @@
}
// add client to list
- {
+ { // scope for mLock
Mutex::Autolock _l(mLock);
wclient = mClients.valueFor(pid);
if (wclient != NULL) {
@@ -1445,15 +2314,20 @@
client = new Client(this, pid);
mClients.add(pid, client);
}
+
+ // frameCount must be a multiple of input buffer size
+ inFrameCount = inputBufferSize/channelCount/sizeof(short);
+ frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount;
+
+ // create new record track. The record track uses one track in mHardwareMixerThread by convention.
+ recordTrack = new MixerThread::RecordTrack(mHardwareMixerThread, client, streamType, sampleRate,
+ format, channelCount, frameCount, flags);
}
-
- // frameCount must be a multiple of input buffer size
- inFrameCount = inputBufferSize/channelCount/sizeof(short);
- frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount;
-
- // create new record track and pass to record thread
- recordTrack = new RecordTrack(this, client, streamType, sampleRate,
- format, channelCount, frameCount);
+ if (recordTrack->getCblk() == NULL) {
+ recordTrack.clear();
+ lStatus = NO_MEMORY;
+ goto Exit;
+ }
// return to handle to client
recordHandle = new RecordHandle(recordTrack);
@@ -1466,97 +2340,22 @@
return recordHandle;
}
-status_t AudioFlinger::startRecord(RecordTrack* recordTrack) {
+status_t AudioFlinger::startRecord(MixerThread::RecordTrack* recordTrack) {
if (mAudioRecordThread != 0) {
return mAudioRecordThread->start(recordTrack);
}
return NO_INIT;
}
-void AudioFlinger::stopRecord(RecordTrack* recordTrack) {
+void AudioFlinger::stopRecord(MixerThread::RecordTrack* recordTrack) {
if (mAudioRecordThread != 0) {
mAudioRecordThread->stop(recordTrack);
}
}
-
// ----------------------------------------------------------------------------
-AudioFlinger::RecordTrack::RecordTrack(
- const sp<AudioFlinger>& audioFlinger,
- const sp<Client>& client,
- int streamType,
- uint32_t sampleRate,
- int format,
- int channelCount,
- int frameCount)
- : TrackBase(audioFlinger, client, streamType, sampleRate, format,
- channelCount, frameCount, 0),
- mOverflow(false)
-{
-}
-
-AudioFlinger::RecordTrack::~RecordTrack()
-{
- mAudioFlinger->audioMixer()->deleteTrackName(mName);
-}
-
-status_t AudioFlinger::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
-{
- audio_track_cblk_t* cblk = this->cblk();
- uint32_t framesAvail;
- uint32_t framesReq = buffer->frameCount;
-
- // Check if last stepServer failed, try to step now
- if (mFlags & TrackBase::STEPSERVER_FAILED) {
- if (!step()) goto getNextBuffer_exit;
- LOGV("stepServer recovered");
- mFlags &= ~TrackBase::STEPSERVER_FAILED;
- }
-
- framesAvail = cblk->framesAvailable_l();
-
- if (LIKELY(framesAvail)) {
- uint32_t s = cblk->server;
- uint32_t bufferEnd = cblk->serverBase + cblk->frameCount;
-
- if (framesReq > framesAvail) {
- framesReq = framesAvail;
- }
- if (s + framesReq > bufferEnd) {
- framesReq = bufferEnd - s;
- }
-
- buffer->raw = getBuffer(s, framesReq);
- if (buffer->raw == 0) goto getNextBuffer_exit;
-
- buffer->frameCount = framesReq;
- return NO_ERROR;
- }
-
-getNextBuffer_exit:
- buffer->raw = 0;
- buffer->frameCount = 0;
- return NOT_ENOUGH_DATA;
-}
-
-status_t AudioFlinger::RecordTrack::start()
-{
- return mAudioFlinger->startRecord(this);
-}
-
-void AudioFlinger::RecordTrack::stop()
-{
- mAudioFlinger->stopRecord(this);
- TrackBase::reset();
- // Force overerrun condition to avoid false overrun callback until first data is
- // read from buffer
- mCblk->flowControlFlag = 1;
-}
-
-// ----------------------------------------------------------------------------
-
-AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::RecordTrack>& recordTrack)
+AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::MixerThread::RecordTrack>& recordTrack)
: BnAudioRecord(),
mRecordTrack(recordTrack)
{
@@ -1588,8 +2387,10 @@
// ----------------------------------------------------------------------------
-AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware) :
+AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware,
+ const sp<AudioFlinger>& audioFlinger) :
mAudioHardware(audioHardware),
+ mAudioFlinger(audioFlinger),
mActive(false)
{
}
@@ -1619,15 +2420,17 @@
input = 0;
}
mRecordTrack.clear();
+ mStopped.signal();
mWaitWorkCV.wait(mLock);
LOGV("AudioRecordThread: loop starting");
if (mRecordTrack != 0) {
input = mAudioHardware->openInputStream(mRecordTrack->format(),
- mRecordTrack->channelCount(),
- mRecordTrack->sampleRate(),
- &mStartStatus);
+ mRecordTrack->channelCount(),
+ mRecordTrack->sampleRate(),
+ &mStartStatus,
+ (AudioSystem::audio_in_acoustics)(mRecordTrack->mFlags >> 16));
if (input != 0) {
inBufferSize = input->bufferSize();
inFrameCount = inBufferSize/input->frameSize();
@@ -1643,12 +2446,14 @@
mWaitWorkCV.signal();
}
mLock.unlock();
- } else if (mRecordTrack != 0){
+ } else if (mRecordTrack != 0) {
buffer.frameCount = inFrameCount;
- if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR)) {
+ if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR &&
+ (int)buffer.frameCount == inFrameCount)) {
LOGV("AudioRecordThread read: %d frames", buffer.frameCount);
- if (input->read(buffer.raw, inBufferSize) < 0) {
+ ssize_t bytesRead = input->read(buffer.raw, inBufferSize);
+ if (bytesRead < 0) {
LOGE("Error reading audio input");
sleep(1);
}
@@ -1677,7 +2482,7 @@
return false;
}
-status_t AudioFlinger::AudioRecordThread::start(RecordTrack* recordTrack)
+status_t AudioFlinger::AudioRecordThread::start(MixerThread::RecordTrack* recordTrack)
{
LOGV("AudioRecordThread::start");
AutoMutex lock(&mLock);
@@ -1690,6 +2495,19 @@
mRecordTrack = recordTrack;
+#ifdef WITH_A2DP
+ { // scope for lock2
+
+ // AudioFlinger::mLock must be locked before calling
+ // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l().
+ AutoMutex lock2(&mAudioFlinger->mLock);
+
+ // Currently there is no way to detect if we are recording over SCO,
+ // so we disable A2DP during any recording.
+ mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_ADDED);
+ }
+#endif
+
// signal thread to start
LOGV("Signal record thread");
mWaitWorkCV.signal();
@@ -1698,11 +2516,24 @@
return mStartStatus;
}
-void AudioFlinger::AudioRecordThread::stop(RecordTrack* recordTrack) {
+void AudioFlinger::AudioRecordThread::stop(MixerThread::RecordTrack* recordTrack) {
LOGV("AudioRecordThread::stop");
AutoMutex lock(&mLock);
if (mActive && (recordTrack == mRecordTrack.get())) {
+#ifdef WITH_A2DP
+ { // scope for lock2
+
+ // AudioFlinger::mLock must be locked before calling
+ // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l().
+ AutoMutex lock2(&mAudioFlinger->mLock);
+
+ // Currently there is no way to detect if we are recording over SCO,
+ // so we disable A2DP during any recording.
+ mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_REMOVED);
+ }
+#endif
mActive = false;
+ mStopped.wait(mLock);
}
}
@@ -1717,6 +2548,22 @@
requestExitAndWait();
}
+status_t AudioFlinger::AudioRecordThread::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ pid_t pid = 0;
+
+ if (mRecordTrack != 0 && mRecordTrack->mClient != 0) {
+ snprintf(buffer, SIZE, "Record client pid: %d\n", mRecordTrack->mClient->pid());
+ result.append(buffer);
+ } else {
+ result.append("No record client\n");
+ }
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
status_t AudioFlinger::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 9ab362a..ab15947 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -22,6 +22,7 @@
#include <sys/types.h>
#include <media/IAudioFlinger.h>
+#include <media/IAudioFlingerClient.h>
#include <media/IAudioTrack.h>
#include <media/IAudioRecord.h>
#include <media/AudioTrack.h>
@@ -32,6 +33,7 @@
#include <utils/MemoryDealer.h>
#include <utils/KeyedVector.h>
#include <utils/SortedVector.h>
+#include <utils/Vector.h>
#include <hardware_legacy/AudioHardwareInterface.h>
@@ -54,18 +56,13 @@
static const nsecs_t kStandbyTimeInNsecs = seconds(3);
-class AudioFlinger : public BnAudioFlinger, protected Thread
+class AudioFlinger : public BnAudioFlinger, public IBinder::DeathRecipient
{
public:
static void instantiate();
virtual status_t dump(int fd, const Vector<String16>& args);
- // Thread virtuals
- virtual bool threadLoop();
- virtual status_t readyToRun();
- virtual void onFirstRef();
-
// IAudioFlinger interface
virtual sp<IAudioTrack> createTrack(
pid_t pid,
@@ -78,11 +75,11 @@
const sp<IMemory>& sharedBuffer,
status_t *status);
- virtual uint32_t sampleRate() const;
- virtual int channelCount() const;
- virtual int format() const;
- virtual size_t frameCount() const;
- virtual size_t latency() const;
+ virtual uint32_t sampleRate(int output) const;
+ virtual int channelCount(int output) const;
+ virtual int format(int output) const;
+ virtual size_t frameCount(int output) const;
+ virtual uint32_t latency(int output) const;
virtual status_t setMasterVolume(float value);
virtual status_t setMasterMute(bool muted);
@@ -107,8 +104,19 @@
virtual bool isMusicActive() const;
+ virtual bool isA2dpEnabled() const;
+
virtual status_t setParameter(const char* key, const char* value);
+ virtual void registerClient(const sp<IAudioFlingerClient>& client);
+
+ virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
+
+ virtual void wakeUp() { mWaitWorkCV.broadcast(); }
+
+ // IBinder::DeathRecipient
+ virtual void binderDied(const wp<IBinder>& who);
+
enum hardware_call_state {
AUDIO_HW_IDLE = 0,
AUDIO_HW_INIT,
@@ -149,23 +157,31 @@
AudioFlinger();
virtual ~AudioFlinger();
- void setOutput(AudioStreamOut* output);
- void doSetOutput(AudioStreamOut* output);
- size_t getOutputFrameCount(AudioStreamOut* output);
+ void setOutput(int outputType);
+ void doSetOutput(int outputType);
#ifdef WITH_A2DP
+ void setA2dpEnabled_l(bool enable);
+ void checkA2dpEnabledChange_l();
+#endif
+ static bool streamForcedToSpeaker(int streamType);
static bool streamDisablesA2dp(int streamType);
- inline bool isA2dpEnabled() const {
- return (mRequestedOutput == mA2dpOutput ||
- (mOutput && mOutput == mA2dpOutput));
- }
- void setA2dpEnabled(bool enable);
+
+ // Management of forced route to speaker for certain track types.
+ enum force_speaker_command {
+ ACTIVE_TRACK_ADDED = 0,
+ ACTIVE_TRACK_REMOVED,
+ CHECK_ROUTE_RESTORE_TIME,
+ FORCE_ROUTE_RESTORE
+ };
+ void handleForcedSpeakerRoute(int command);
+#ifdef WITH_A2DP
+ void handleStreamDisablesA2dp_l(int command);
#endif
// Internal dump utilites.
status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
status_t dumpClients(int fd, const Vector<String16>& args);
- status_t dumpTracks(int fd, const Vector<String16>& args);
status_t dumpInternals(int fd, const Vector<String16>& args);
// --- Client ---
@@ -184,168 +200,347 @@
};
- // --- Track ---
class TrackHandle;
class RecordHandle;
class AudioRecordThread;
- // base for record and playback
- class TrackBase : public AudioBufferProvider, public RefBase {
-
+
+ // --- MixerThread ---
+ class MixerThread : public Thread {
public:
- enum track_state {
- IDLE,
- TERMINATED,
- STOPPED,
- RESUMING,
- ACTIVE,
- PAUSING,
- PAUSED
+
+ // --- Track ---
+
+ // base for record and playback
+ class TrackBase : public AudioBufferProvider, public RefBase {
+
+ public:
+ enum track_state {
+ IDLE,
+ TERMINATED,
+ STOPPED,
+ RESUMING,
+ ACTIVE,
+ PAUSING,
+ PAUSED
+ };
+
+ enum track_flags {
+ STEPSERVER_FAILED = 0x01, // StepServer could not acquire cblk->lock mutex
+ SYSTEM_FLAGS_MASK = 0x0000ffffUL,
+ // The upper 16 bits are used for track-specific flags.
+ };
+
+ TrackBase(const sp<MixerThread>& mixerThread,
+ const sp<Client>& client,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount,
+ uint32_t flags,
+ const sp<IMemory>& sharedBuffer);
+ ~TrackBase();
+
+ virtual status_t start() = 0;
+ virtual void stop() = 0;
+ sp<IMemory> getCblk() const;
+
+ protected:
+ friend class MixerThread;
+ friend class RecordHandle;
+ friend class AudioRecordThread;
+
+ TrackBase(const TrackBase&);
+ TrackBase& operator = (const TrackBase&);
+
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
+ virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
+
+ audio_track_cblk_t* cblk() const {
+ return mCblk;
+ }
+
+ int type() const {
+ return mStreamType;
+ }
+
+ int format() const {
+ return mFormat;
+ }
+
+ int channelCount() const ;
+
+ int sampleRate() const;
+
+ void* getBuffer(uint32_t offset, uint32_t frames) const;
+
+ int name() const {
+ return mName;
+ }
+
+ bool isStopped() const {
+ return mState == STOPPED;
+ }
+
+ bool isTerminated() const {
+ return mState == TERMINATED;
+ }
+
+ bool step();
+ void reset();
+
+ sp<MixerThread> mMixerThread;
+ sp<Client> mClient;
+ sp<IMemory> mCblkMemory;
+ audio_track_cblk_t* mCblk;
+ int mStreamType;
+ void* mBuffer;
+ void* mBufferEnd;
+ uint32_t mFrameCount;
+ int mName;
+ // we don't really need a lock for these
+ int mState;
+ int mClientTid;
+ uint8_t mFormat;
+ uint32_t mFlags;
};
- enum track_flags {
- STEPSERVER_FAILED = 0x01 // StepServer could not acquire cblk->lock mutex
+ // playback track
+ class Track : public TrackBase {
+ public:
+ Track( const sp<MixerThread>& mixerThread,
+ const sp<Client>& client,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount,
+ const sp<IMemory>& sharedBuffer);
+ ~Track();
+
+ void dump(char* buffer, size_t size);
+ virtual status_t start();
+ virtual void stop();
+ void pause();
+
+ void flush();
+ void destroy();
+ void mute(bool);
+ void setVolume(float left, float right);
+
+ protected:
+ friend class MixerThread;
+ friend class AudioFlinger;
+ friend class AudioFlinger::TrackHandle;
+
+ Track(const Track&);
+ Track& operator = (const Track&);
+
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+
+ bool isMuted() const {
+ return (mMute || mMixerThread->mStreamTypes[mStreamType].mute);
+ }
+
+ bool isPausing() const {
+ return mState == PAUSING;
+ }
+
+ bool isPaused() const {
+ return mState == PAUSED;
+ }
+
+ bool isReady() const;
+
+ void setPaused() { mState = PAUSED; }
+ void reset();
+
+ // we don't really need a lock for these
+ float mVolume[2];
+ volatile bool mMute;
+ // FILLED state is used for suppressing volume ramp at begin of playing
+ enum {FS_FILLING, FS_FILLED, FS_ACTIVE};
+ mutable uint8_t mFillingUpStatus;
+ int8_t mRetryCount;
+ sp<IMemory> mSharedBuffer;
+ bool mResetDone;
+ }; // end of Track
+
+ // record track
+ class RecordTrack : public TrackBase {
+ public:
+ RecordTrack(const sp<MixerThread>& mixerThread,
+ const sp<Client>& client,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount,
+ uint32_t flags);
+ ~RecordTrack();
+
+ virtual status_t start();
+ virtual void stop();
+
+ bool overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
+ bool setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
+
+ private:
+ friend class AudioFlinger;
+ friend class AudioFlinger::RecordHandle;
+ friend class AudioFlinger::AudioRecordThread;
+ friend class MixerThread;
+
+ RecordTrack(const Track&);
+ RecordTrack& operator = (const Track&);
+
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+
+ bool mOverflow;
};
- TrackBase( const sp<AudioFlinger>& audioFlinger,
- const sp<Client>& client,
+ // playback track
+ class OutputTrack : public Track {
+ public:
+
+ class Buffer: public AudioBufferProvider::Buffer {
+ public:
+ int16_t *mBuffer;
+ };
+
+ OutputTrack( const sp<MixerThread>& mixerThread,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount);
+ ~OutputTrack();
+
+ virtual status_t start();
+ virtual void stop();
+ void write(int16_t* data, uint32_t frames);
+ bool bufferQueueEmpty() { return (mBufferQueue.size() == 0) ? true : false; }
+
+ private:
+
+ status_t obtainBuffer(AudioBufferProvider::Buffer* buffer);
+ void clearBufferQueue();
+
+ sp<MixerThread> mOutputMixerThread;
+ Vector < Buffer* > mBufferQueue;
+ AudioBufferProvider::Buffer mOutBuffer;
+ uint32_t mFramesWritten;
+
+ }; // end of OutputTrack
+
+ MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int outputType);
+ virtual ~MixerThread();
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ // Thread virtuals
+ virtual bool threadLoop();
+ virtual status_t readyToRun();
+ virtual void onFirstRef();
+
+ virtual uint32_t sampleRate() const;
+ virtual int channelCount() const;
+ virtual int format() const;
+ virtual size_t frameCount() const;
+ virtual uint32_t latency() const;
+
+ virtual status_t setMasterVolume(float value);
+ virtual status_t setMasterMute(bool muted);
+
+ virtual float masterVolume() const;
+ virtual bool masterMute() const;
+
+ virtual status_t setStreamVolume(int stream, float value);
+ virtual status_t setStreamMute(int stream, bool muted);
+
+ virtual float streamVolume(int stream) const;
+ virtual bool streamMute(int stream) const;
+
+ bool isMusicActive() const;
+
+
+ sp<Track> createTrack_l(
+ const sp<AudioFlinger::Client>& client,
int streamType,
uint32_t sampleRate,
int format,
int channelCount,
int frameCount,
- const sp<IMemory>& sharedBuffer);
- ~TrackBase();
-
- virtual status_t start() = 0;
- virtual void stop() = 0;
- sp<IMemory> getCblk() const;
-
- protected:
- friend class AudioFlinger;
- friend class RecordHandle;
- friend class AudioRecordThread;
-
- TrackBase(const TrackBase&);
- TrackBase& operator = (const TrackBase&);
-
- virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
- virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
-
- audio_track_cblk_t* cblk() const {
- return mCblk;
- }
-
- int type() const {
- return mStreamType;
- }
-
- int format() const {
- return mFormat;
- }
-
- int channelCount() const ;
-
- int sampleRate() const;
-
- void* getBuffer(uint32_t offset, uint32_t frames) const;
-
- int name() const {
- return mName;
- }
-
- bool isStopped() const {
- return mState == STOPPED;
- }
-
- bool isTerminated() const {
- return mState == TERMINATED;
- }
-
- bool step();
- void reset();
-
- sp<AudioFlinger> mAudioFlinger;
- sp<Client> mClient;
- sp<IMemory> mCblkMemory;
- audio_track_cblk_t* mCblk;
- int mStreamType;
- void* mBuffer;
- void* mBufferEnd;
- uint32_t mFrameCount;
- int mName;
- // we don't really need a lock for these
- int mState;
- int mClientTid;
- uint8_t mFormat;
- uint8_t mFlags;
- };
-
- // playback track
- class Track : public TrackBase {
- public:
- Track( const sp<AudioFlinger>& audioFlinger,
- const sp<Client>& client,
- int streamType,
- uint32_t sampleRate,
- int format,
- int channelCount,
- int frameCount,
- const sp<IMemory>& sharedBuffer);
- ~Track();
-
- void dump(char* buffer, size_t size);
- virtual status_t start();
- virtual void stop();
- void pause();
-
- void flush();
- void destroy();
- void mute(bool);
- void setVolume(float left, float right);
+ const sp<IMemory>& sharedBuffer,
+ status_t *status);
+
+ void getTracks_l(SortedVector < sp<Track> >& tracks,
+ SortedVector < wp<Track> >& activeTracks);
+ void putTracks_l(SortedVector < sp<Track> >& tracks,
+ SortedVector < wp<Track> >& activeTracks);
+ void setOuputTrack(OutputTrack *track) { mOutputTrack = track; }
+
+ struct stream_type_t {
+ stream_type_t()
+ : volume(1.0f),
+ mute(false)
+ {
+ }
+ float volume;
+ bool mute;
+ };
private:
+
+
friend class AudioFlinger;
- friend class TrackHandle;
+ friend class Track;
+ friend class TrackBase;
+ friend class RecordTrack;
+
+ MixerThread(const Client&);
+ MixerThread& operator = (const MixerThread&);
+
+ status_t addTrack_l(const sp<Track>& track);
+ void removeTrack_l(wp<Track> track, int name);
+ void destroyTrack_l(const sp<Track>& track);
+ int getTrackName_l();
+ void deleteTrackName_l(int name);
+ void addActiveTrack_l(const wp<Track>& t);
+ void removeActiveTrack_l(const wp<Track>& t);
+ size_t getOutputFrameCount();
- Track(const Track&);
- Track& operator = (const Track&);
+ status_t dumpInternals(int fd, const Vector<String16>& args);
+ status_t dumpTracks(int fd, const Vector<String16>& args);
+
+ sp<AudioFlinger> mAudioFlinger;
+ SortedVector< wp<Track> > mActiveTracks;
+ SortedVector< sp<Track> > mTracks;
+ stream_type_t mStreamTypes[AudioSystem::NUM_STREAM_TYPES];
+ AudioMixer* mAudioMixer;
+ AudioStreamOut* mOutput;
+ int mOutputType;
+ uint32_t mSampleRate;
+ size_t mFrameCount;
+ int mChannelCount;
+ int mFormat;
+ int16_t* mMixBuffer;
+ float mMasterVolume;
+ bool mMasterMute;
+ nsecs_t mLastWriteTime;
+ int mNumWrites;
+ int mNumDelayedWrites;
+ bool mStandby;
+ bool mInWrite;
+ sp <OutputTrack> mOutputTrack;
+ };
- virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
-
- bool isMuted() const {
- return mMute;
- }
-
- bool isPausing() const {
- return mState == PAUSING;
- }
-
- bool isPaused() const {
- return mState == PAUSED;
- }
-
- bool isReady() const;
-
- void setPaused() { mState = PAUSED; }
- void reset();
-
- // we don't really need a lock for these
- float mVolume[2];
- volatile bool mMute;
- // FILLED state is used for suppressing volume ramp at begin of playing
- enum {FS_FILLING, FS_FILLED, FS_ACTIVE};
- mutable uint8_t mFillingUpStatus;
- int8_t mRetryCount;
- sp<IMemory> mSharedBuffer;
- bool mResetDone;
- }; // end of Track
-
+
friend class AudioBuffer;
class TrackHandle : public android::BnAudioTrack {
public:
- TrackHandle(const sp<Track>& track);
+ TrackHandle(const sp<MixerThread::Track>& track);
virtual ~TrackHandle();
virtual status_t start();
virtual void stop();
@@ -357,70 +552,20 @@
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
private:
- sp<Track> mTrack;
- };
-
- struct stream_type_t {
- stream_type_t()
- : volume(1.0f),
- mute(false)
- {
- }
- float volume;
- bool mute;
+ sp<MixerThread::Track> mTrack;
};
friend class Client;
- friend class Track;
+ friend class MixerThread::Track;
void removeClient(pid_t pid);
- status_t addTrack(const sp<Track>& track);
- void removeTrack(wp<Track> track, int name);
- void remove_track_l(wp<Track> track, int name);
- void destroyTrack(const sp<Track>& track);
- void addActiveTrack(const wp<Track>& track);
- void removeActiveTrack(const wp<Track>& track);
- AudioMixer* audioMixer() {
- return mAudioMixer;
- }
-
- // record track
- class RecordTrack : public TrackBase {
- public:
- RecordTrack( const sp<AudioFlinger>& audioFlinger,
- const sp<Client>& client,
- int streamType,
- uint32_t sampleRate,
- int format,
- int channelCount,
- int frameCount);
- ~RecordTrack();
-
- virtual status_t start();
- virtual void stop();
-
- bool overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
- bool setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
-
- private:
- friend class AudioFlinger;
- friend class RecordHandle;
- friend class AudioRecordThread;
-
- RecordTrack(const Track&);
- RecordTrack& operator = (const Track&);
-
- virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
-
- bool mOverflow;
- };
class RecordHandle : public android::BnAudioRecord {
public:
- RecordHandle(const sp<RecordTrack>& recordTrack);
+ RecordHandle(const sp<MixerThread::RecordTrack>& recordTrack);
virtual ~RecordHandle();
virtual status_t start();
virtual void stop();
@@ -428,72 +573,66 @@
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
private:
- sp<RecordTrack> mRecordTrack;
+ sp<MixerThread::RecordTrack> mRecordTrack;
};
// record thread
class AudioRecordThread : public Thread
{
public:
- AudioRecordThread(AudioHardwareInterface* audioHardware);
+ AudioRecordThread(AudioHardwareInterface* audioHardware, const sp<AudioFlinger>& audioFlinger);
virtual ~AudioRecordThread();
virtual bool threadLoop();
virtual status_t readyToRun() { return NO_ERROR; }
virtual void onFirstRef() {}
- status_t start(RecordTrack* recordTrack);
- void stop(RecordTrack* recordTrack);
+ status_t start(MixerThread::RecordTrack* recordTrack);
+ void stop(MixerThread::RecordTrack* recordTrack);
void exit();
+ status_t dump(int fd, const Vector<String16>& args);
private:
AudioRecordThread();
AudioHardwareInterface *mAudioHardware;
- sp<RecordTrack> mRecordTrack;
+ sp<AudioFlinger> mAudioFlinger;
+ sp<MixerThread::RecordTrack> mRecordTrack;
Mutex mLock;
Condition mWaitWorkCV;
+ Condition mStopped;
volatile bool mActive;
status_t mStartStatus;
};
friend class AudioRecordThread;
+ friend class MixerThread;
- status_t startRecord(RecordTrack* recordTrack);
- void stopRecord(RecordTrack* recordTrack);
+ status_t startRecord(MixerThread::RecordTrack* recordTrack);
+ void stopRecord(MixerThread::RecordTrack* recordTrack);
- mutable Mutex mHardwareLock;
- mutable Mutex mLock;
- mutable Condition mWaitWorkCV;
+ mutable Mutex mHardwareLock;
+ mutable Mutex mLock;
+ mutable Condition mWaitWorkCV;
+
DefaultKeyedVector< pid_t, wp<Client> > mClients;
- SortedVector< wp<Track> > mActiveTracks;
- SortedVector< sp<Track> > mTracks;
- float mMasterVolume;
- uint32_t mMasterRouting;
- bool mMasterMute;
- stream_type_t mStreamTypes[AudioTrack::NUM_STREAM_TYPES];
- AudioMixer* mHardwareAudioMixer;
- AudioMixer* mA2dpAudioMixer;
- AudioMixer* mAudioMixer;
+ sp<MixerThread> mA2dpMixerThread;
+ sp<MixerThread> mHardwareMixerThread;
AudioHardwareInterface* mAudioHardware;
AudioHardwareInterface* mA2dpAudioInterface;
- AudioStreamOut* mHardwareOutput;
- AudioStreamOut* mA2dpOutput;
- AudioStreamOut* mOutput;
- AudioStreamOut* mRequestedOutput;
sp<AudioRecordThread> mAudioRecordThread;
- uint32_t mSampleRate;
- size_t mFrameCount;
- int mChannelCount;
- int mFormat;
- int16_t* mMixBuffer;
+ bool mA2dpEnabled;
+ bool mNotifyA2dpChange;
mutable int mHardwareStatus;
- nsecs_t mLastWriteTime;
- int mNumWrites;
- int mNumDelayedWrites;
- bool mStandby;
- bool mInWrite;
+ SortedVector< wp<IBinder> > mNotificationClients;
+ int mForcedSpeakerCount;
int mA2dpDisableCount;
+
+ // true if A2DP should resume when mA2dpDisableCount returns to zero
bool mA2dpSuppressed;
+ uint32_t mSavedRoute;
+ uint32_t mForcedRoute;
+ nsecs_t mRouteRestoreTime;
+ bool mMusicMuteSaved;
};
// ----------------------------------------------------------------------------
diff --git a/libs/audioflinger/AudioHardwareGeneric.cpp b/libs/audioflinger/AudioHardwareGeneric.cpp
index e455186..62beada 100644
--- a/libs/audioflinger/AudioHardwareGeneric.cpp
+++ b/libs/audioflinger/AudioHardwareGeneric.cpp
@@ -93,7 +93,8 @@
}
AudioStreamIn* AudioHardwareGeneric::openInputStream(
- int format, int channelCount, uint32_t sampleRate, status_t *status)
+ int format, int channelCount, uint32_t sampleRate, status_t *status,
+ AudioSystem::audio_in_acoustics acoustics)
{
AutoMutex lock(mLock);
@@ -107,7 +108,7 @@
// create new output stream
AudioStreamInGeneric* in = new AudioStreamInGeneric();
- status_t lStatus = in->set(this, mFd, format, channelCount, sampleRate);
+ status_t lStatus = in->set(this, mFd, format, channelCount, sampleRate, acoustics);
if (status) {
*status = lStatus;
}
@@ -246,7 +247,8 @@
int fd,
int format,
int channels,
- uint32_t rate)
+ uint32_t rate,
+ AudioSystem::audio_in_acoustics acoustics)
{
// FIXME: remove logging
LOGD("AudioStreamInGeneric::set(%p, %d, %d, %d, %u)", hw, fd, format, channels, rate);
diff --git a/libs/audioflinger/AudioHardwareGeneric.h b/libs/audioflinger/AudioHardwareGeneric.h
index a7822e1..c949aa1 100644
--- a/libs/audioflinger/AudioHardwareGeneric.h
+++ b/libs/audioflinger/AudioHardwareGeneric.h
@@ -47,7 +47,7 @@
virtual size_t bufferSize() const { return 4096; }
virtual int channelCount() const { return 2; }
virtual int format() const { return AudioSystem::PCM_16_BIT; }
- virtual uint32_t latency() const { return 0; }
+ virtual uint32_t latency() const { return 20; }
virtual status_t setVolume(float volume) { return INVALID_OPERATION; }
virtual ssize_t write(const void* buffer, size_t bytes);
virtual status_t standby();
@@ -69,7 +69,8 @@
int mFd,
int format,
int channelCount,
- uint32_t sampleRate);
+ uint32_t sampleRate,
+ AudioSystem::audio_in_acoustics acoustics);
uint32_t sampleRate() const { return 8000; }
virtual size_t bufferSize() const { return 320; }
@@ -114,7 +115,8 @@
int format,
int channelCount,
uint32_t sampleRate,
- status_t *status);
+ status_t *status,
+ AudioSystem::audio_in_acoustics acoustics);
void closeOutputStream(AudioStreamOutGeneric* out);
void closeInputStream(AudioStreamInGeneric* in);
diff --git a/libs/audioflinger/AudioHardwareStub.cpp b/libs/audioflinger/AudioHardwareStub.cpp
index e9f3d69..b13cb1c 100644
--- a/libs/audioflinger/AudioHardwareStub.cpp
+++ b/libs/audioflinger/AudioHardwareStub.cpp
@@ -56,10 +56,11 @@
}
AudioStreamIn* AudioHardwareStub::openInputStream(
- int format, int channelCount, uint32_t sampleRate, status_t *status)
+ int format, int channelCount, uint32_t sampleRate,
+ status_t *status, AudioSystem::audio_in_acoustics acoustics)
{
AudioStreamInStub* in = new AudioStreamInStub();
- status_t lStatus = in->set(format, channelCount, sampleRate);
+ status_t lStatus = in->set(format, channelCount, sampleRate, acoustics);
if (status) {
*status = lStatus;
}
@@ -142,7 +143,8 @@
// ----------------------------------------------------------------------------
-status_t AudioStreamInStub::set(int format, int channels, uint32_t rate)
+status_t AudioStreamInStub::set(int format, int channels, uint32_t rate,
+ AudioSystem::audio_in_acoustics acoustics)
{
if ((format == AudioSystem::PCM_16_BIT) &&
(channels == channelCount()) &&
diff --git a/libs/audioflinger/AudioHardwareStub.h b/libs/audioflinger/AudioHardwareStub.h
index 24736ed..d406424 100644
--- a/libs/audioflinger/AudioHardwareStub.h
+++ b/libs/audioflinger/AudioHardwareStub.h
@@ -43,7 +43,7 @@
class AudioStreamInStub : public AudioStreamIn {
public:
- virtual status_t set(int format, int channelCount, uint32_t sampleRate);
+ virtual status_t set(int format, int channelCount, uint32_t sampleRate, AudioSystem::audio_in_acoustics acoustics);
virtual uint32_t sampleRate() const { return 8000; }
virtual size_t bufferSize() const { return 320; }
virtual int channelCount() const { return 1; }
@@ -81,7 +81,8 @@
int format,
int channelCount,
uint32_t sampleRate,
- status_t *status);
+ status_t *status,
+ AudioSystem::audio_in_acoustics acoustics);
protected:
virtual status_t doRouting() { return NO_ERROR; }
diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk
index d14cebf..496e271 100644
--- a/libs/surfaceflinger/Android.mk
+++ b/libs/surfaceflinger/Android.mk
@@ -15,8 +15,8 @@
LayerBlur.cpp \
LayerBitmap.cpp \
LayerDim.cpp \
- LayerScreenshot.cpp \
- RFBServer.cpp \
+ LayerOrientationAnim.cpp \
+ OrientationAnimation.cpp \
SurfaceFlinger.cpp \
Tokenizer.cpp \
Transform.cpp \
@@ -38,7 +38,8 @@
libcorecg \
libsgl \
libpixelflinger \
- libGLES_CM
+ libEGL \
+ libGLESv1_CM
LOCAL_C_INCLUDES := \
$(call include-path-for, corecg graphics)
diff --git a/libs/surfaceflinger/BootAnimation.cpp b/libs/surfaceflinger/BootAnimation.cpp
index d18f59a..2b30336 100644
--- a/libs/surfaceflinger/BootAnimation.cpp
+++ b/libs/surfaceflinger/BootAnimation.cpp
@@ -39,7 +39,9 @@
#include <core/SkBitmap.h>
#include <images/SkImageDecoder.h>
-#include <GLES/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <EGL/eglext.h>
#include "BootAnimation.h"
@@ -47,32 +49,28 @@
// ---------------------------------------------------------------------------
-BootAnimation::BootAnimation(const sp<ISurfaceComposer>& composer)
-: Thread(false)
-{
+BootAnimation::BootAnimation(const sp<ISurfaceComposer>& composer) :
+ Thread(false) {
mSession = SurfaceComposerClient::clientForConnection(
composer->createConnection()->asBinder());
}
-BootAnimation::~BootAnimation()
-{
+BootAnimation::~BootAnimation() {
}
-void BootAnimation::onFirstRef()
-{
+void BootAnimation::onFirstRef() {
run("BootAnimation", PRIORITY_DISPLAY);
}
-const sp<SurfaceComposerClient>& BootAnimation::session() const
-{
+const sp<SurfaceComposerClient>& BootAnimation::session() const {
return mSession;
}
-status_t BootAnimation::initTexture(
- Texture* texture, AssetManager& assets, const char* name)
-{
+status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
+ const char* name) {
Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
- if (!asset) return NO_INIT;
+ if (!asset)
+ return NO_INIT;
SkBitmap bitmap;
SkImageDecoder::DecodeMemory(asset->getBuffer(false), asset->getLength(),
&bitmap, SkBitmap::kNo_Config, SkImageDecoder::kDecodePixels_Mode);
@@ -84,32 +82,32 @@
bitmap.lockPixels();
const int w = bitmap.width();
- const int h = bitmap.height();
+ const int h = bitmap.height();
const void* p = bitmap.getPixels();
-
+
GLint crop[4] = { 0, h, w, -h };
texture->w = w;
texture->h = h;
glGenTextures(1, &texture->name);
glBindTexture(GL_TEXTURE_2D, texture->name);
-
- switch(bitmap.getConfig()) {
+
+ switch (bitmap.getConfig()) {
case SkBitmap::kA8_Config:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0,
- GL_ALPHA, GL_UNSIGNED_BYTE, p);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA,
+ GL_UNSIGNED_BYTE, p);
break;
case SkBitmap::kARGB_4444_Config:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0,
- GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, p);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
+ GL_UNSIGNED_SHORT_4_4_4_4, p);
break;
case SkBitmap::kARGB_8888_Config:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, p);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, p);
break;
case SkBitmap::kRGB_565_Config:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0,
- GL_RGB, GL_UNSIGNED_SHORT_5_6_5, p);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
+ GL_UNSIGNED_SHORT_5_6_5, p);
break;
default:
break;
@@ -123,8 +121,7 @@
return NO_ERROR;
}
-status_t BootAnimation::readyToRun()
-{
+status_t BootAnimation::readyToRun() {
mAssets.addDefaultAssets();
DisplayInfo dinfo;
@@ -133,32 +130,27 @@
return -1;
// create the native surface
- sp<Surface> s = session()->createSurface(getpid(), 0,
- dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
+ sp<Surface> s = session()->createSurface(getpid(), 0, dinfo.w, dinfo.h,
+ PIXEL_FORMAT_RGB_565);
session()->openTransaction();
s->setLayer(0x40000000);
session()->closeTransaction();
// initialize opengl and egl
- const EGLint attribs[] = {
- EGL_RED_SIZE, 5,
- EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5,
- EGL_DEPTH_SIZE, 0,
- EGL_NONE
- };
+ const EGLint attribs[] = { EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6,
+ EGL_BLUE_SIZE, 5, EGL_DEPTH_SIZE, 0, EGL_NONE };
EGLint w, h, dummy;
EGLint numConfigs;
EGLConfig config;
EGLSurface surface;
EGLContext context;
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- eglInitialize(display, NULL, NULL);
eglChooseConfig(display, attribs, &config, 1, &numConfigs);
- surface = eglCreateWindowSurface(
- display, config, new EGLNativeWindowSurface(s), NULL);
-
+ mNativeWindowSurface = new EGLNativeWindowSurface(s);
+ surface = eglCreateWindowSurface(display, config,
+ mNativeWindowSurface.get(), NULL);
+
context = eglCreateContext(display, config, NULL, NULL);
eglQuerySurface(display, surface, EGL_WIDTH, &w);
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
@@ -167,7 +159,7 @@
mContext = context;
mSurface = surface;
mWidth = w;
- mHeight= h;
+ mHeight = h;
mFlingerSurface = s;
// initialize GL
@@ -180,25 +172,21 @@
return NO_ERROR;
}
-void BootAnimation::requestExit()
-{
+void BootAnimation::requestExit() {
mBarrier.open();
Thread::requestExit();
}
-bool BootAnimation::threadLoop()
-{
+bool BootAnimation::threadLoop() {
bool r = android();
- eglMakeCurrent(mDisplay, 0, 0, 0);
- eglDestroyContext(mDisplay, mContext);
+ eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglDestroyContext(mDisplay, mContext);
eglDestroySurface(mDisplay, mSurface);
- eglTerminate(mDisplay);
+ mNativeWindowSurface.clear();
return r;
}
-
-bool BootAnimation::android()
-{
+bool BootAnimation::android() {
initTexture(&mAndroid[0], mAssets, "images/android_320x480.png");
initTexture(&mAndroid[1], mAssets, "images/boot_robot.png");
initTexture(&mAndroid[2], mAssets, "images/boot_robot_glow.png");
@@ -219,9 +207,9 @@
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
const int steps = 8;
- for (int i=1 ; i<steps ; i++) {
+ for (int i = 1; i < steps; i++) {
float fade = i / float(steps);
- glColor4f(1, 1, 1, fade*fade);
+ glColor4f(1, 1, 1, fade * fade);
glClear(GL_COLOR_BUFFER_BIT);
glDrawTexiOES(0, 0, 0, mAndroid[0].w, mAndroid[0].h);
eglSwapBuffers(mDisplay, mSurface);
@@ -232,79 +220,73 @@
glDisable(GL_BLEND);
glDrawTexiOES(0, 0, 0, mAndroid[0].w, mAndroid[0].h);
eglSwapBuffers(mDisplay, mSurface);
-
-
+
// update rect for the robot
const int x = mWidth - mAndroid[1].w - 33;
- const int y = (mHeight - mAndroid[1].h)/2 - 1;
- const Rect updateRect(x, y, x+mAndroid[1].w, y+mAndroid[1].h);
+ const int y = (mHeight - mAndroid[1].h) / 2 - 1;
+ const Rect updateRect(x, y, x + mAndroid[1].w, y + mAndroid[1].h);
// draw and update only what we need
- eglSwapRectangleANDROID(mDisplay, mSurface,
- updateRect.left, updateRect.top,
- updateRect.width(), updateRect.height());
+ mNativeWindowSurface->setSwapRectangle(updateRect.left,
+ updateRect.top, updateRect.width(), updateRect.height());
glEnable(GL_SCISSOR_TEST);
- glScissor(updateRect.left, mHeight-updateRect.bottom,
- updateRect.width(), updateRect.height());
+ glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
+ updateRect.height());
const nsecs_t startTime = systemTime();
- do
- {
+ do {
// glow speed and shape
nsecs_t time = systemTime() - startTime;
- float t = ((4.0f/(360.0f*us2ns(16667))) * time);
+ float t = ((4.0f / (360.0f * us2ns(16667))) * time);
t = t - floorf(t);
- const float fade = 0.5f + 0.5f*sinf(t * 2*M_PI);
+ const float fade = 0.5f + 0.5f * sinf(t * 2 * M_PI);
// fade the glow in and out
glDisable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, mAndroid[2].name);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glColor4f(fade, fade, fade, fade);
- glDrawTexiOES(updateRect.left, mHeight-updateRect.bottom, 0,
+ glDrawTexiOES(updateRect.left, mHeight - updateRect.bottom, 0,
updateRect.width(), updateRect.height());
// draw the robot
glEnable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- glDrawTexiOES(updateRect.left, mHeight-updateRect.bottom, 0,
+ glDrawTexiOES(updateRect.left, mHeight - updateRect.bottom, 0,
updateRect.width(), updateRect.height());
// make sure sleep a lot to not take too much CPU away from
// the boot process. With this "glow" animation there is no
// visible difference.
- usleep(16667*4);
+ usleep(16667 * 4);
eglSwapBuffers(mDisplay, mSurface);
} while (!exitPending());
-
-
+
glDeleteTextures(1, &mAndroid[0].name);
glDeleteTextures(1, &mAndroid[1].name);
glDeleteTextures(1, &mAndroid[2].name);
return false;
}
-
-bool BootAnimation::cylon()
-{
+bool BootAnimation::cylon() {
// initialize the textures...
- initTexture(&mLeftTrail, mAssets, "images/cylon_left.png");
+ initTexture(&mLeftTrail, mAssets, "images/cylon_left.png");
initTexture(&mRightTrail, mAssets, "images/cylon_right.png");
initTexture(&mBrightSpot, mAssets, "images/cylon_dot.png");
int w = mWidth;
int h = mHeight;
- const Point c(w/2 , h/2);
+ const Point c(w / 2, h / 2);
const GLint amplitude = 60;
- const int scx = c.x - amplitude - mBrightSpot.w/2;
- const int scy = c.y - mBrightSpot.h/2;
- const int scw = amplitude*2 + mBrightSpot.w;
+ const int scx = c.x - amplitude - mBrightSpot.w / 2;
+ const int scy = c.y - mBrightSpot.h / 2;
+ const int scw = amplitude * 2 + mBrightSpot.w;
const int sch = mBrightSpot.h;
- const Rect updateRect(scx, h-scy-sch, scx+scw, h-scy);
+ const Rect updateRect(scx, h - scy - sch, scx + scw, h - scy);
// erase screen
glDisable(GL_SCISSOR_TEST);
@@ -314,33 +296,29 @@
glClear(GL_COLOR_BUFFER_BIT);
- eglSwapRectangleANDROID(mDisplay, mSurface,
- updateRect.left, updateRect.top,
- updateRect.width(), updateRect.height());
+ mNativeWindowSurface->setSwapRectangle(updateRect.left,
+ updateRect.top, updateRect.width(), updateRect.height());
glEnable(GL_SCISSOR_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-
// clear the screen to white
Point p;
float t = 0;
float alpha = 1.0f;
const nsecs_t startTime = systemTime();
nsecs_t fadeTime = 0;
-
- do
- {
+
+ do {
// Set scissor in interesting area
- glScissor(scx, scy, scw, sch);
+ glScissor(scx, scy, scw, sch);
// erase screen
glClear(GL_COLOR_BUFFER_BIT);
-
// compute wave
- const float a = (t * 2*M_PI) - M_PI/2;
+ const float a = (t * 2 * M_PI) - M_PI / 2;
const float sn = sinf(a);
const float cs = cosf(a);
GLint x = GLint(amplitude * sn);
@@ -350,50 +328,50 @@
if (derivative > 0) {
// vanishing trail...
- p.x = (-amplitude + c.x) - mBrightSpot.w/2;
- p.y = c.y-mLeftTrail.h/2;
- float fade = 2.0f*(0.5f-t);
+ p.x = (-amplitude + c.x) - mBrightSpot.w / 2;
+ p.y = c.y - mLeftTrail.h / 2;
+ float fade = 2.0f * (0.5f - t);
//fade *= fade;
glColor4f(fade, fade, fade, fade);
glBindTexture(GL_TEXTURE_2D, mLeftTrail.name);
glDrawTexiOES(p.x, p.y, 0, mLeftTrail.w, mLeftTrail.h);
// trail...
- p.x = (x + c.x) - (mRightTrail.w + mBrightSpot.w/2) + 16;
- p.y = c.y-mRightTrail.h/2;
- fade = t<0.25f ? t*4.0f : 1.0f;
+ p.x = (x + c.x) - (mRightTrail.w + mBrightSpot.w / 2) + 16;
+ p.y = c.y - mRightTrail.h / 2;
+ fade = t < 0.25f ? t * 4.0f : 1.0f;
fade *= fade;
glColor4f(fade, fade, fade, fade);
glBindTexture(GL_TEXTURE_2D, mRightTrail.name);
glDrawTexiOES(p.x, p.y, 0, mRightTrail.w, mRightTrail.h);
- } else {
+ } else {
// vanishing trail..
- p.x = (amplitude + c.x) - (mRightTrail.w + mBrightSpot.w/2) + 16;
- p.y = c.y-mRightTrail.h/2;
- float fade = 2.0f*(0.5f-(t-0.5f));
+ p.x = (amplitude + c.x) - (mRightTrail.w + mBrightSpot.w / 2) + 16;
+ p.y = c.y - mRightTrail.h / 2;
+ float fade = 2.0f * (0.5f - (t - 0.5f));
//fade *= fade;
glColor4f(fade, fade, fade, fade);
glBindTexture(GL_TEXTURE_2D, mRightTrail.name);
glDrawTexiOES(p.x, p.y, 0, mRightTrail.w, mRightTrail.h);
// trail...
- p.x = (x + c.x) - mBrightSpot.w/2;
- p.y = c.y-mLeftTrail.h/2;
- fade = t<0.5f+0.25f ? (t-0.5f)*4.0f : 1.0f;
+ p.x = (x + c.x) - mBrightSpot.w / 2;
+ p.y = c.y - mLeftTrail.h / 2;
+ fade = t < 0.5f + 0.25f ? (t - 0.5f) * 4.0f : 1.0f;
fade *= fade;
glColor4f(fade, fade, fade, fade);
glBindTexture(GL_TEXTURE_2D, mLeftTrail.name);
glDrawTexiOES(p.x, p.y, 0, mLeftTrail.w, mLeftTrail.h);
}
- const Point p( x + c.x-mBrightSpot.w/2, c.y-mBrightSpot.h/2 );
+ const Point p(x + c.x - mBrightSpot.w / 2, c.y - mBrightSpot.h / 2);
glBindTexture(GL_TEXTURE_2D, mBrightSpot.name);
- glColor4f(1,0.5,0.5,1);
+ glColor4f(1, 0.5, 0.5, 1);
glDrawTexiOES(p.x, p.y, 0, mBrightSpot.w, mBrightSpot.h);
// update animation
nsecs_t time = systemTime() - startTime;
- t = ((4.0f/(360.0f*us2ns(16667))) * time);
+ t = ((4.0f / (360.0f * us2ns(16667))) * time);
t = t - floorf(t);
eglSwapBuffers(mDisplay, mSurface);
@@ -406,7 +384,7 @@
alpha = 1.0f - ((float(time) * 6.0f) / float(s2ns(1)));
session()->openTransaction();
- mFlingerSurface->setAlpha(alpha*alpha);
+ mFlingerSurface->setAlpha(alpha * alpha);
session()->closeTransaction();
}
} while (alpha > 0);
@@ -421,4 +399,5 @@
// ---------------------------------------------------------------------------
-}; // namespace android
+}
+; // namespace android
diff --git a/libs/surfaceflinger/BootAnimation.h b/libs/surfaceflinger/BootAnimation.h
index a4a6d49..b20cea0 100644
--- a/libs/surfaceflinger/BootAnimation.h
+++ b/libs/surfaceflinger/BootAnimation.h
@@ -26,7 +26,8 @@
#include <ui/ISurfaceComposer.h>
#include <ui/SurfaceComposerClient.h>
-#include <GLES/egl.h>
+#include <EGL/egl.h>
+#include <GLES/gl.h>
#include "Barrier.h"
@@ -35,6 +36,7 @@
namespace android {
class AssetManager;
+class EGLNativeWindowSurface;
// ---------------------------------------------------------------------------
@@ -74,6 +76,7 @@
EGLDisplay mContext;
EGLDisplay mSurface;
sp<Surface> mFlingerSurface;
+ sp<EGLNativeWindowSurface> mNativeWindowSurface;
Barrier mBarrier;
};
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 92588fa..f14d7e9 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -21,14 +21,16 @@
#include <string.h>
#include <math.h>
-#include <GLES/egl.h>
-
#include <cutils/properties.h>
#include <utils/Log.h>
#include <ui/EGLDisplaySurface.h>
+#include <GLES/gl.h>
+#include <EGL/eglext.h>
+
+
#include "DisplayHardware/DisplayHardware.h"
#include <hardware/copybit.h>
@@ -136,26 +138,19 @@
const char* const egl_extensions = eglQueryString(
display, EGL_EXTENSIONS);
- const char* egl_extensions_config = egl_extensions;
-
- if (strstr(egl_extensions, "EGL_ANDROID_query_string_config")) {
- egl_extensions_config = eglQueryStringConfigANDROID(
- display, config, EGL_EXTENSIONS);
- }
-
LOGI("EGL informations:");
LOGI("# of configs : %d", numConfigs);
LOGI("vendor : %s", eglQueryString(display, EGL_VENDOR));
LOGI("version : %s", eglQueryString(display, EGL_VERSION));
LOGI("extensions: %s", egl_extensions);
- LOGI("ext/config: %s", egl_extensions_config);
LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
- if (strstr(egl_extensions_config, "EGL_ANDROID_swap_rectangle")) {
- mFlags |= SWAP_RECTANGLE_EXTENSION;
- // TODO: get the real "update_on_demand" behavior
- mFlags |= UPDATE_ON_DEMAND;
- }
+ // TODO: get this from the devfb driver (probably should be HAL module)
+ mFlags |= SWAP_RECTANGLE_EXTENSION;
+
+ // TODO: get the real "update_on_demand" behavior (probably should be HAL module)
+ mFlags |= UPDATE_ON_DEMAND;
+
if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) {
if (dummy == EGL_SLOW_CONFIG)
mFlags |= SLOW_CONFIG;
@@ -173,9 +168,6 @@
if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
if (dummy == EGL_BUFFER_PRESERVED) {
mFlags |= BUFFER_PRESERVED;
- if (strstr(egl_extensions_config, "EGL_ANDROID_copy_front_to_back")) {
- mFlags |= COPY_BACK_EXTENSION;
- }
}
}
@@ -330,8 +322,7 @@
if (mFlags & SWAP_RECTANGLE_EXTENSION) {
const Rect& b(newDirty.bounds());
- eglSwapRectangleANDROID(
- dpy, surface,
+ mDisplaySurface->setSwapRectangle(
b.left, b.top, b.width(), b.height());
}
@@ -352,3 +343,11 @@
{
eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
}
+
+void DisplayHardware::copyFrontToImage(const copybit_image_t& front) const {
+ mDisplaySurface->copyFrontToImage(front);
+}
+
+void DisplayHardware::copyBackToImage(const copybit_image_t& front) const {
+ mDisplaySurface->copyBackToImage(front);
+}
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
index df97b60..550a4d1 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -22,7 +22,7 @@
#include <ui/PixelFormat.h>
#include <ui/Region.h>
-#include <GLES/egl.h>
+#include <EGL/egl.h>
#include "DisplayHardware/DisplayHardwareBase.h"
@@ -39,7 +39,6 @@
{
public:
enum {
- COPY_BACK_EXTENSION = 0x00000001,
DIRECT_TEXTURE = 0x00000002,
SWAP_RECTANGLE_EXTENSION= 0x00000004,
COPY_BITS_EXTENSION = 0x00000008,
@@ -80,6 +79,9 @@
copybit_device_t* getBlitEngine() const { return mBlitEngine; }
overlay_control_device_t* getOverlayEngine() const { return mOverlayEngine; }
+ void copyFrontToImage(const copybit_image_t& front) const;
+ void copyBackToImage(const copybit_image_t& front) const;
+
Rect bounds() const {
return Rect(mWidth, mHeight);
}
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index bdefba3..0cf53f7 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -23,6 +23,11 @@
#include <utils/Errors.h>
#include <utils/Log.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <hardware/hardware.h>
+
#include "clz.h"
#include "LayerBase.h"
#include "LayerBlur.h"
@@ -111,6 +116,12 @@
mDrawingState.h = h;
}
}
+void LayerBase::forceVisibilityTransaction() {
+ // this can be called without SurfaceFlinger.mStateLock, but if we
+ // can atomically increment the sequence number, it doesn't matter.
+ android_atomic_inc(&mCurrentState.sequence);
+ requestTransaction();
+}
bool LayerBase::requestTransaction() {
int32_t old = setTransactionFlags(eTransactionNeeded);
return ((old & eTransactionNeeded) == 0);
@@ -350,6 +361,10 @@
return;
}
}
+
+ // reset GL state
+ glEnable(GL_SCISSOR_TEST);
+
onDraw(clip);
/*
@@ -391,6 +406,7 @@
Rect r;
Region::iterator iterator(clip);
if (iterator) {
+ glEnable(GL_SCISSOR_TEST);
glVertexPointer(2, GL_FIXED, 0, mVertices);
while (iterator.iterate(&r)) {
const GLint sy = fbHeight - (r.top + r.height());
@@ -401,7 +417,7 @@
}
void LayerBase::drawWithOpenGL(const Region& clip,
- GLint textureName, const GGLSurface& t) const
+ GLint textureName, const GGLSurface& t, int transform) const
{
const DisplayHardware& hw(graphicPlane(0).displayHardware());
const uint32_t fbHeight = hw.getHeight();
@@ -473,6 +489,12 @@
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
+
+ if (transform == HAL_TRANSFORM_ROT_90) {
+ glTranslatef(0, 1, 0);
+ glRotatef(-90, 0, 0, 1);
+ }
+
if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
// find the smallest power-of-two that will accommodate our surface
GLuint tw = 1 << (31 - clz(t.width));
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index 5e14dc8..a020f44 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -86,8 +86,8 @@
uint32_t z;
uint8_t alpha;
uint8_t flags;
- uint8_t sequence; // changes when visible regions can change
- uint8_t reserved;
+ uint8_t reserved[2];
+ int32_t sequence; // changes when visible regions can change
uint32_t tint;
Transform transform;
Region transparentRegion;
@@ -104,11 +104,11 @@
void commitTransaction(bool skipSize);
bool requestTransaction();
-
+ void forceVisibilityTransaction();
+
uint32_t getTransactionFlags(uint32_t flags);
uint32_t setTransactionFlags(uint32_t flags);
- void validateVisibility(const Transform& globalTransform);
Rect visibleBounds() const;
void drawRegion(const Region& reg) const;
@@ -162,7 +162,12 @@
* the bitmap (as opposed to the size of the drawing state).
*/
virtual Point getPhysicalSize() const;
-
+
+ /**
+ * validateVisibility - cache a bunch of things
+ */
+ virtual void validateVisibility(const Transform& globalTransform);
+
/**
* lockPageFlip - called each time the screen is redrawn and returns whether
* the visible regions need to be recomputed (this is a fairly heavy
@@ -188,10 +193,15 @@
* needsBlending - true if this surface needs blending
*/
virtual bool needsBlending() const { return false; }
-
+
/**
- * isSecure - true if this surface is secure, that is if it prevents a
- * screenshot to be taken,
+ * transformed -- true is this surface needs a to be transformed
+ */
+ virtual bool transformed() const { return mTransformed; }
+
+ /**
+ * isSecure - true if this surface is secure, that is if it prevents
+ * screenshots or vns servers.
*/
virtual bool isSecure() const { return false; }
@@ -210,7 +220,6 @@
}
int32_t getOrientation() const { return mOrientation; }
- bool transformed() const { return mTransformed; }
int tx() const { return mLeft; }
int ty() const { return mTop; }
@@ -221,7 +230,9 @@
GLuint createTexture() const;
void drawWithOpenGL(const Region& clip,
- GLint textureName, const GGLSurface& surface) const;
+ GLint textureName,
+ const GGLSurface& surface,
+ int transform = 0) const;
void clearWithOpenGL(const Region& clip) const;
@@ -320,8 +331,7 @@
*params = mParams;
}
- virtual status_t registerBuffers(int w, int h, int hstride, int vstride,
- PixelFormat format, const sp<IMemoryHeap>& heap)
+ virtual status_t registerBuffers(const ISurface::BufferHeap& buffers)
{ return INVALID_OPERATION; }
virtual void postBuffer(ssize_t offset) { }
virtual void unregisterBuffers() { };
diff --git a/libs/surfaceflinger/LayerBitmap.cpp b/libs/surfaceflinger/LayerBitmap.cpp
index 7c98857..e844350 100644
--- a/libs/surfaceflinger/LayerBitmap.cpp
+++ b/libs/surfaceflinger/LayerBitmap.cpp
@@ -69,18 +69,15 @@
return NO_ERROR;
}
+ PixelFormatInfo info;
+ getPixelFormatInfo(format, &info);
+
uint32_t allocFlags = MemoryDealer::PAGE_ALIGNED;
const uint32_t align = 4; // must match GL_UNPACK_ALIGNMENT
- const uint32_t Bpp = bytesPerPixel(format);
+ const uint32_t Bpp = info.bytesPerPixel;
uint32_t stride = (w + (alignment-1)) & ~(alignment-1);
stride = ((stride * Bpp + (align-1)) & ~(align-1)) / Bpp;
- size_t size = stride * h * Bpp;
- if (format == PIXEL_FORMAT_YCbCr_422_SP ||
- format == PIXEL_FORMAT_YCbCr_420_SP) {
- // in YUV planar, bitsPerPixel is for the Y plane
- size = (size * bitsPerPixel(format)) / 8;
- }
-
+ size_t size = info.getScanlineSize(stride) * h;
if (allocFlags & MemoryDealer::PAGE_ALIGNED) {
size_t pagesize = getpagesize();
size = (size + (pagesize-1)) & ~(pagesize-1);
diff --git a/libs/surfaceflinger/LayerBitmap.h b/libs/surfaceflinger/LayerBitmap.h
index 4c2eb50..9ad64c4 100644
--- a/libs/surfaceflinger/LayerBitmap.h
+++ b/libs/surfaceflinger/LayerBitmap.h
@@ -70,9 +70,6 @@
void getBitmapSurface(copybit_image_t* img) const;
private:
- LayerBitmap(const LayerBitmap& rhs);
- LayerBitmap& operator = (const LayerBitmap& rhs);
-
sp<MemoryDealer> mAllocator;
sp<IMemory> mBitsMemory;
uint32_t mAllocFlags;
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
index efadbcf..d3e456f 100644
--- a/libs/surfaceflinger/LayerBlur.cpp
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -23,6 +23,9 @@
#include <utils/Errors.h>
#include <utils/Log.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
#include "BlurFilter.h"
#include "LayerBlur.h"
#include "SurfaceFlinger.h"
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index c9cebf4..00fab70 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -25,6 +25,9 @@
#include <utils/Log.h>
#include <utils/StopWatch.h>
+#include <utils/IPCThreadState.h>
+#include <utils/IServiceManager.h>
+
#include <ui/PixelFormat.h>
#include <ui/EGLDisplaySurface.h>
@@ -129,18 +132,24 @@
}
}
+bool LayerBuffer::transformed() const
+{
+ sp<Source> source(getSource());
+ if (LIKELY(source != 0))
+ return source->transformed();
+ return false;
+}
+
/**
* This creates a "buffer" source for this surface
*/
-status_t LayerBuffer::registerBuffers(int w, int h, int hstride, int vstride,
- PixelFormat format, const sp<IMemoryHeap>& memoryHeap)
+status_t LayerBuffer::registerBuffers(const ISurface::BufferHeap& buffers)
{
Mutex::Autolock _l(mLock);
if (mSource != 0)
return INVALID_OPERATION;
- sp<BufferSource> source = new BufferSource(*this, w, h,
- hstride, vstride, format, memoryHeap);
+ sp<BufferSource> source = new BufferSource(*this, buffers);
status_t result = source->getStatus();
if (result == NO_ERROR) {
@@ -194,13 +203,39 @@
mOwner = 0;
}
-status_t LayerBuffer::SurfaceBuffer::registerBuffers(
- int w, int h, int hs, int vs,
- PixelFormat format, const sp<IMemoryHeap>& heap)
+status_t LayerBuffer::SurfaceBuffer::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+ case REGISTER_BUFFERS:
+ case UNREGISTER_BUFFERS:
+ case CREATE_OVERLAY:
+ {
+ // codes that require permission check
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int self_pid = getpid();
+ if (LIKELY(pid != self_pid)) {
+ // we're called from a different process, do the real check
+ if (!checkCallingPermission(
+ String16("android.permission.ACCESS_SURFACE_FLINGER")))
+ {
+ const int uid = ipc->getCallingUid();
+ LOGE("Permission Denial: "
+ "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ }
+ }
+ }
+ return LayerBaseClient::Surface::onTransact(code, data, reply, flags);
+}
+
+status_t LayerBuffer::SurfaceBuffer::registerBuffers(const ISurface::BufferHeap& buffers)
{
LayerBuffer* owner(getOwner());
if (owner)
- return owner->registerBuffers(w, h, hs, vs, format, heap);
+ return owner->registerBuffers(buffers);
return NO_INIT;
}
@@ -237,23 +272,20 @@
// LayerBuffer::Buffer
// ============================================================================
-LayerBuffer::Buffer::Buffer(const sp<IMemoryHeap>& heap, ssize_t offset,
- int w, int h, int hs, int vs, int f)
-: mHeap(heap)
+LayerBuffer::Buffer::Buffer(const ISurface::BufferHeap& buffers, ssize_t offset)
+ : mBufferHeap(buffers)
{
NativeBuffer& src(mNativeBuffer);
src.crop.l = 0;
src.crop.t = 0;
- src.crop.r = w;
- src.crop.b = h;
- src.img.w = hs ?: w;
- src.img.h = vs ?: h;
- src.img.format = f;
+ src.crop.r = buffers.w;
+ src.crop.b = buffers.h;
+ src.img.w = buffers.hor_stride ?: buffers.w;
+ src.img.h = buffers.ver_stride ?: buffers.h;
+ src.img.format = buffers.format;
src.img.offset = offset;
- src.img.base = heap->base();
- src.img.fd = heap->heapID();
- // FIXME: make sure this buffer lies within the heap, in which case, set
- // mHeap to null
+ src.img.base = buffers.heap->base();
+ src.img.fd = buffers.heap->heapID();
}
LayerBuffer::Buffer::~Buffer()
@@ -283,41 +315,55 @@
}
void LayerBuffer::Source::unregisterBuffers() {
}
+bool LayerBuffer::Source::transformed() const {
+ return mLayer.mTransformed;
+}
// ---------------------------------------------------------------------------
LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer,
- int w, int h, int hstride, int vstride,
- PixelFormat format, const sp<IMemoryHeap>& memoryHeap)
- : Source(layer), mStatus(NO_ERROR), mTextureName(-1U)
+ const ISurface::BufferHeap& buffers)
+ : Source(layer), mStatus(NO_ERROR),
+ mBufferSize(0), mTextureName(-1U)
{
- if (memoryHeap == NULL) {
+ if (buffers.heap == NULL) {
// this is allowed, but in this case, it is illegal to receive
// postBuffer(). The surface just erases the framebuffer with
// fully transparent pixels.
- mHeap.clear();
- mWidth = w;
- mHeight = h;
+ mBufferHeap = buffers;
mLayer.setNeedsBlending(false);
return;
}
- status_t err = (memoryHeap->heapID() >= 0) ? NO_ERROR : NO_INIT;
+ status_t err = (buffers.heap->heapID() >= 0) ? NO_ERROR : NO_INIT;
if (err != NO_ERROR) {
+ LOGE("LayerBuffer::BufferSource: invalid heap (%s)", strerror(err));
+ mStatus = err;
+ return;
+ }
+
+ PixelFormatInfo info;
+ err = getPixelFormatInfo(buffers.format, &info);
+ if (err != NO_ERROR) {
+ LOGE("LayerBuffer::BufferSource: invalid format %d (%s)",
+ buffers.format, strerror(err));
mStatus = err;
return;
}
- // TODO: validate format/parameters
- mHeap = memoryHeap;
- mWidth = w;
- mHeight = h;
- mHStride = hstride;
- mVStride = vstride;
- mFormat = format;
- PixelFormatInfo info;
- getPixelFormatInfo(format, &info);
- mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0);
+ if (buffers.hor_stride<0 || buffers.ver_stride<0) {
+ LOGE("LayerBuffer::BufferSource: invalid parameters "
+ "(w=%d, h=%d, xs=%d, ys=%d)",
+ buffers.w, buffers.h, buffers.hor_stride, buffers.ver_stride);
+ mStatus = BAD_VALUE;
+ return;
+ }
+
+ mBufferHeap = buffers;
+ mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0);
+ mBufferSize = info.getScanlineSize(buffers.hor_stride)*buffers.ver_stride;
+ mLayer.forceVisibilityTransaction();
+
}
LayerBuffer::BufferSource::~BufferSource()
@@ -329,21 +375,24 @@
void LayerBuffer::BufferSource::postBuffer(ssize_t offset)
{
- sp<IMemoryHeap> heap;
- int w, h, hs, vs, f;
+ ISurface::BufferHeap buffers;
{ // scope for the lock
Mutex::Autolock _l(mLock);
- w = mWidth;
- h = mHeight;
- hs= mHStride;
- vs= mVStride;
- f = mFormat;
- heap = mHeap;
+ buffers = mBufferHeap;
+ if (buffers.heap != 0) {
+ const size_t memorySize = buffers.heap->getSize();
+ if ((size_t(offset) + mBufferSize) > memorySize) {
+ LOGE("LayerBuffer::BufferSource::postBuffer() "
+ "invalid buffer (offset=%d, size=%d, heap-size=%d",
+ int(offset), int(mBufferSize), int(memorySize));
+ return;
+ }
+ }
}
sp<Buffer> buffer;
- if (heap != 0) {
- buffer = new LayerBuffer::Buffer(heap, offset, w, h, hs, vs, f);
+ if (buffers.heap != 0) {
+ buffer = new LayerBuffer::Buffer(buffers, offset);
if (buffer->getStatus() != NO_ERROR)
buffer.clear();
setBuffer(buffer);
@@ -354,7 +403,7 @@
void LayerBuffer::BufferSource::unregisterBuffers()
{
Mutex::Autolock _l(mLock);
- mHeap.clear();
+ mBufferHeap.heap.clear();
mBuffer.clear();
mLayer.invalidate();
}
@@ -371,6 +420,11 @@
mBuffer = buffer;
}
+bool LayerBuffer::BufferSource::transformed() const
+{
+ return mBufferHeap.transform ? true : Source::transformed();
+}
+
void LayerBuffer::BufferSource::onDraw(const Region& clip) const
{
sp<Buffer> buffer(getBuffer());
@@ -417,7 +471,7 @@
if (UNLIKELY(mTemporaryDealer == 0)) {
// allocate a memory-dealer for this the first time
mTemporaryDealer = mLayer.mFlinger->getSurfaceHeapManager()
- ->createHeap(ISurfaceComposer::eHardware);
+ ->createHeap(ISurfaceComposer::eHardware);
mTempBitmap.init(mTemporaryDealer);
}
@@ -447,16 +501,31 @@
copybit_image_t dst;
hw.getDisplaySurface(&dst);
const copybit_rect_t& drect
- = reinterpret_cast<const copybit_rect_t&>(transformedBounds);
+ = reinterpret_cast<const copybit_rect_t&>(transformedBounds);
const State& s(mLayer.drawingState());
region_iterator it(clip);
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, mLayer.getOrientation());
+
+ // pick the right orientation for this buffer
+ int orientation = mLayer.getOrientation();
+ if (UNLIKELY(mBufferHeap.transform)) {
+ Transform rot90;
+ GraphicPlane::orientationToTransfrom(
+ ISurfaceComposer::eOrientation90, 0, 0, &rot90);
+ const Transform& planeTransform(mLayer.graphicPlane(0).transform());
+ const Layer::State& s(mLayer.drawingState());
+ Transform tr(planeTransform * s.transform * rot90);
+ orientation = tr.getOrientation();
+ }
+
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, orientation);
copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
- copybit->set_parameter(copybit, COPYBIT_DITHER,
- s.flags & ISurfaceComposer::eLayerDither ?
- COPYBIT_ENABLE : COPYBIT_DISABLE);
+ copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
+
err = copybit->stretch(copybit,
&dst, &src.img, &drect, &src.crop, &it);
+ if (err != NO_ERROR) {
+ LOGE("copybit failed (%s)", strerror(err));
+ }
}
if (!can_use_copybit || err) {
@@ -475,10 +544,11 @@
t.data = (GGLubyte*)(intptr_t(src.img.base) + src.img.offset);
const Region dirty(Rect(t.width, t.height));
mLayer.loadTexture(dirty, mTextureName, t, w, h);
- mLayer.drawWithOpenGL(clip, mTextureName, t);
+ mLayer.drawWithOpenGL(clip, mTextureName, t, mBufferHeap.transform);
}
}
+
// ---------------------------------------------------------------------------
LayerBuffer::OverlaySource::OverlaySource(LayerBuffer& layer,
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index 6e3d49f..2dc77f1 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -22,7 +22,7 @@
#include <utils/IMemory.h>
#include <private/ui/LayerState.h>
-#include <GLES/eglnatives.h>
+#include <EGL/eglnatives.h>
#include "LayerBase.h"
#include "LayerBitmap.h"
@@ -46,6 +46,7 @@
virtual void onVisibilityResolved(const Transform& planeTransform);
virtual void postBuffer(ssize_t offset);
virtual void unregisterBuffers();
+ virtual bool transformed() const;
protected:
LayerBuffer& mLayer;
};
@@ -67,9 +68,9 @@
virtual void onDraw(const Region& clip) const;
virtual uint32_t doTransaction(uint32_t flags);
virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
+ virtual bool transformed() const;
- status_t registerBuffers(int w, int h, int hstride, int vstride,
- PixelFormat format, const sp<IMemoryHeap>& heap);
+ 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);
@@ -89,10 +90,9 @@
class Buffer : public LightRefBase<Buffer> {
public:
- Buffer(const sp<IMemoryHeap>& heap, ssize_t offset,
- int w, int h, int hs, int vs, int f);
+ Buffer(const ISurface::BufferHeap& buffers, ssize_t offset);
inline status_t getStatus() const {
- return mHeap!=0 ? NO_ERROR : NO_INIT;
+ return mBufferHeap.heap!=0 ? NO_ERROR : NO_INIT;
}
inline const NativeBuffer& getBuffer() const {
return mNativeBuffer;
@@ -103,15 +103,13 @@
Buffer(const Buffer& rhs);
~Buffer();
private:
- sp<IMemoryHeap> mHeap;
- NativeBuffer mNativeBuffer;
+ ISurface::BufferHeap mBufferHeap;
+ NativeBuffer mNativeBuffer;
};
class BufferSource : public Source {
public:
- BufferSource(LayerBuffer& layer,
- int w, int h, int hstride, int vstride,
- PixelFormat format, const sp<IMemoryHeap>& heap);
+ BufferSource(LayerBuffer& layer, const ISurface::BufferHeap& buffers);
virtual ~BufferSource();
status_t getStatus() const { return mStatus; }
@@ -121,16 +119,13 @@
virtual void onDraw(const Region& clip) const;
virtual void postBuffer(ssize_t offset);
virtual void unregisterBuffers();
+ virtual bool transformed() const;
private:
mutable Mutex mLock;
- sp<IMemoryHeap> mHeap;
sp<Buffer> mBuffer;
status_t mStatus;
- int mWidth;
- int mHeight;
- int mHStride;
- int mVStride;
- int mFormat;
+ ISurface::BufferHeap mBufferHeap;
+ size_t mBufferSize;
mutable sp<MemoryDealer> mTemporaryDealer;
mutable LayerBitmap mTempBitmap;
mutable GLuint mTextureName;
@@ -186,8 +181,9 @@
public:
SurfaceBuffer(SurfaceID id, LayerBuffer* owner);
virtual ~SurfaceBuffer();
- virtual status_t registerBuffers(int w, int h, int hstride, int vstride,
- PixelFormat format, const sp<IMemoryHeap>& heap);
+ virtual status_t onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+ virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);
virtual void postBuffer(ssize_t offset);
virtual void unregisterBuffers();
virtual sp<OverlayRef> createOverlay(
diff --git a/libs/surfaceflinger/LayerOrientationAnim.cpp b/libs/surfaceflinger/LayerOrientationAnim.cpp
new file mode 100644
index 0000000..2b72d7c
--- /dev/null
+++ b/libs/surfaceflinger/LayerOrientationAnim.cpp
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <core/SkBitmap.h>
+
+#include <ui/EGLDisplaySurface.h>
+
+#include "LayerBase.h"
+#include "LayerOrientationAnim.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+#include "OrientationAnimation.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerOrientationAnim::typeInfo = LayerBase::typeInfo | 0x80;
+const char* const LayerOrientationAnim::typeID = "LayerOrientationAnim";
+
+// ---------------------------------------------------------------------------
+
+LayerOrientationAnim::LayerOrientationAnim(
+ SurfaceFlinger* flinger, DisplayID display,
+ OrientationAnimation* anim,
+ const LayerBitmap& bitmap,
+ const LayerBitmap& bitmapIn)
+ : LayerBase(flinger, display), mAnim(anim),
+ mBitmap(bitmap), mBitmapIn(bitmapIn),
+ mTextureName(-1), mTextureNameIn(-1)
+{
+ mStartTime = systemTime();
+ mFinishTime = 0;
+ mOrientationCompleted = false;
+ mFirstRedraw = false;
+ mLastNormalizedTime = 0;
+ mLastScale = 0;
+ mNeedsBlending = false;
+}
+
+LayerOrientationAnim::~LayerOrientationAnim()
+{
+ if (mTextureName != -1U) {
+ LayerBase::deletedTextures.add(mTextureName);
+ }
+ if (mTextureNameIn != -1U) {
+ LayerBase::deletedTextures.add(mTextureNameIn);
+ }
+}
+
+bool LayerOrientationAnim::needsBlending() const
+{
+ return mNeedsBlending;
+}
+
+Point LayerOrientationAnim::getPhysicalSize() const
+{
+ const GraphicPlane& plane(graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ return Point(hw.getWidth(), hw.getHeight());
+}
+
+void LayerOrientationAnim::validateVisibility(const Transform&)
+{
+ const Layer::State& s(drawingState());
+ const Transform tr(s.transform);
+ const Point size(getPhysicalSize());
+ uint32_t w = size.x;
+ uint32_t h = size.y;
+ mTransformedBounds = tr.makeBounds(w, h);
+ mLeft = tr.tx();
+ mTop = tr.ty();
+ transparentRegionScreen.clear();
+ mTransformed = true;
+ mCanUseCopyBit = false;
+ copybit_device_t* copybit = mFlinger->getBlitEngine();
+ if (copybit) {
+ mCanUseCopyBit = true;
+ }
+}
+
+void LayerOrientationAnim::onOrientationCompleted()
+{
+ mFinishTime = systemTime();
+ mOrientationCompleted = true;
+ mFirstRedraw = true;
+ mNeedsBlending = true;
+ mFlinger->invalidateLayerVisibility(this);
+}
+
+void LayerOrientationAnim::onDraw(const Region& clip) const
+{
+ // Animation...
+ const float MIN_SCALE = 0.5f;
+ const float DURATION = ms2ns(200);
+ const float BOUNCES_PER_SECOND = 1.618f;
+ const float BOUNCES_AMPLITUDE = 1.0f/32.0f;
+
+ const nsecs_t now = systemTime();
+ float scale, alpha;
+
+ if (mOrientationCompleted) {
+ if (mFirstRedraw) {
+ mFirstRedraw = false;
+
+ // make a copy of what's on screen
+ copybit_image_t image;
+ mBitmapIn.getBitmapSurface(&image);
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ hw.copyBackToImage(image);
+
+ // and erase the screen for this round
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // FIXME: code below is gross
+ mNeedsBlending = false;
+ LayerOrientationAnim* self(const_cast<LayerOrientationAnim*>(this));
+ mFlinger->invalidateLayerVisibility(self);
+ }
+
+ // make sure pick-up where we left off
+ const float duration = DURATION * mLastNormalizedTime;
+ const float normalizedTime = (float(now - mFinishTime) / duration);
+ if (normalizedTime <= 1.0f) {
+ const float squaredTime = normalizedTime*normalizedTime;
+ scale = (1.0f - mLastScale)*squaredTime + mLastScale;
+ alpha = (1.0f - normalizedTime);
+ alpha *= alpha;
+ alpha *= alpha;
+ } else {
+ mAnim->onAnimationFinished();
+ scale = 1.0f;
+ alpha = 0.0f;
+ }
+ } else {
+ const float normalizedTime = float(now - mStartTime) / DURATION;
+ if (normalizedTime <= 1.0f) {
+ mLastNormalizedTime = normalizedTime;
+ const float squaredTime = normalizedTime*normalizedTime;
+ scale = (MIN_SCALE-1.0f)*squaredTime + 1.0f;
+ alpha = 1.0f;
+ } else {
+ mLastNormalizedTime = 1.0f;
+ const float to_seconds = DURATION / seconds(1);
+ const float phi = BOUNCES_PER_SECOND *
+ (((normalizedTime - 1.0f) * to_seconds)*M_PI*2);
+ scale = MIN_SCALE + BOUNCES_AMPLITUDE * (1.0f - cosf(phi));
+ alpha = 1.0f;
+ }
+ mLastScale = scale;
+ }
+ drawScaled(scale, alpha);
+}
+
+void LayerOrientationAnim::drawScaled(float f, float alpha) const
+{
+ copybit_image_t dst;
+ const GraphicPlane& plane(graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ hw.getDisplaySurface(&dst);
+
+ // clear screen
+ // TODO: with update on demand, we may be able
+ // to not erase the screen at all during the animation
+ if (!mOrientationCompleted) {
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+
+ const int w = dst.w*f;
+ const int h = dst.h*f;
+ const int xc = uint32_t(dst.w-w)/2;
+ const int yc = uint32_t(dst.h-h)/2;
+ const copybit_rect_t drect = { xc, yc, xc+w, yc+h };
+
+ copybit_image_t src;
+ mBitmap.getBitmapSurface(&src);
+ const copybit_rect_t srect = { 0, 0, src.w, src.h };
+
+ int err = NO_ERROR;
+ const int can_use_copybit = canUseCopybit();
+ if (can_use_copybit) {
+ copybit_device_t* copybit = mFlinger->getBlitEngine();
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+ copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
+
+ if (alpha < 1.0f) {
+ copybit_image_t srcIn;
+ mBitmapIn.getBitmapSurface(&srcIn);
+ region_iterator it(Region(Rect( drect.l, drect.t, drect.r, drect.b )));
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
+ err = copybit->stretch(copybit, &dst, &srcIn, &drect, &srect, &it);
+ }
+
+ if (!err && alpha > 0.0f) {
+ region_iterator it(Region(Rect( drect.l, drect.t, drect.r, drect.b )));
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, int(alpha*255));
+ err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+ }
+ LOGE_IF(err != NO_ERROR, "copybit failed (%s)", strerror(err));
+ }
+ if (!can_use_copybit || err) {
+ GGLSurface t;
+ t.version = sizeof(GGLSurface);
+ t.width = src.w;
+ t.height = src.h;
+ t.stride = src.w;
+ t.vstride= src.h;
+ t.format = src.format;
+ t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+
+ Transform tr;
+ tr.set(f,0,0,f);
+ tr.set(xc, yc);
+
+ // FIXME: we should not access mVertices and mDrawingState like that,
+ // but since we control the animation, we know it's going to work okay.
+ // eventually we'd need a more formal way of doing things like this.
+ LayerOrientationAnim& self(const_cast<LayerOrientationAnim&>(*this));
+ tr.transform(self.mVertices[0], 0, 0);
+ tr.transform(self.mVertices[1], 0, src.h);
+ tr.transform(self.mVertices[2], src.w, src.h);
+ tr.transform(self.mVertices[3], src.w, 0);
+ if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
+ // Too slow to do this in software
+ self.mDrawingState.flags |= ISurfaceComposer::eLayerFilter;
+ }
+
+ if (alpha < 1.0f) {
+ copybit_image_t src;
+ mBitmapIn.getBitmapSurface(&src);
+ t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+ if (UNLIKELY(mTextureNameIn == -1LU)) {
+ mTextureNameIn = createTexture();
+ GLuint w=0, h=0;
+ const Region dirty(Rect(t.width, t.height));
+ loadTexture(dirty, mTextureNameIn, t, w, h);
+ }
+ self.mDrawingState.alpha = 255;
+ const Region clip(Rect( drect.l, drect.t, drect.r, drect.b ));
+ drawWithOpenGL(clip, mTextureName, t);
+ }
+
+ t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+ if (UNLIKELY(mTextureName == -1LU)) {
+ mTextureName = createTexture();
+ GLuint w=0, h=0;
+ const Region dirty(Rect(t.width, t.height));
+ loadTexture(dirty, mTextureName, t, w, h);
+ }
+ self.mDrawingState.alpha = int(alpha*255);
+ const Region clip(Rect( drect.l, drect.t, drect.r, drect.b ));
+ drawWithOpenGL(clip, mTextureName, t);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/LayerOrientationAnim.h b/libs/surfaceflinger/LayerOrientationAnim.h
new file mode 100644
index 0000000..7367685
--- /dev/null
+++ b/libs/surfaceflinger/LayerOrientationAnim.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_LAYER_ORIENTATION_ANIM_H
+#define ANDROID_LAYER_ORIENTATION_ANIM_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/threads.h>
+#include <utils/Parcel.h>
+
+#include "LayerBase.h"
+#include "LayerBitmap.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+class OrientationAnimation;
+
+class LayerOrientationAnim : public LayerBase
+{
+public:
+ static const uint32_t typeInfo;
+ static const char* const typeID;
+ virtual char const* getTypeID() const { return typeID; }
+ virtual uint32_t getTypeInfo() const { return typeInfo; }
+
+ LayerOrientationAnim(SurfaceFlinger* flinger, DisplayID display,
+ OrientationAnimation* anim,
+ const LayerBitmap& zoomOut,
+ const LayerBitmap& zoomIn);
+ virtual ~LayerOrientationAnim();
+
+ void onOrientationCompleted();
+
+ virtual void onDraw(const Region& clip) const;
+ virtual Point getPhysicalSize() const;
+ virtual void validateVisibility(const Transform& globalTransform);
+ virtual bool needsBlending() const;
+ virtual bool isSecure() const { return false; }
+private:
+ void drawScaled(float scale, float alpha) const;
+
+ OrientationAnimation* mAnim;
+ LayerBitmap mBitmap;
+ LayerBitmap mBitmapIn;
+ nsecs_t mStartTime;
+ nsecs_t mFinishTime;
+ bool mOrientationCompleted;
+ mutable bool mFirstRedraw;
+ mutable float mLastNormalizedTime;
+ mutable float mLastScale;
+ mutable GLuint mTextureName;
+ mutable GLuint mTextureNameIn;
+ mutable bool mNeedsBlending;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_ORIENTATION_ANIM_H
diff --git a/libs/surfaceflinger/LayerScreenshot.h b/libs/surfaceflinger/LayerScreenshot.h
deleted file mode 100644
index 2d9a8ec..0000000
--- a/libs/surfaceflinger/LayerScreenshot.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_LAYER_SCREENSHOT_H
-#define ANDROID_LAYER_SCREENSHOT_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <utils/threads.h>
-#include <utils/Parcel.h>
-
-#include "LayerBase.h"
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-class LayerScreenshot : public LayerBase
-{
-public:
- static const uint32_t typeInfo;
- static const char* const typeID;
- virtual char const* getTypeID() const { return typeID; }
- virtual uint32_t getTypeInfo() const { return typeInfo; }
-
- LayerScreenshot(SurfaceFlinger* flinger, DisplayID display);
- virtual ~LayerScreenshot();
-
- virtual void onDraw(const Region& clip) const;
- virtual bool needsBlending() const { return true; }
- virtual bool isSecure() const { return false; }
-
- void takeScreenshot(Mutex& lock, Parcel* reply);
-
-private:
- mutable Condition mCV;
- Parcel* mReply;
-};
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_LAYER_SCREENSHOT_H
diff --git a/libs/surfaceflinger/OrientationAnimation.cpp b/libs/surfaceflinger/OrientationAnimation.cpp
new file mode 100644
index 0000000..f6f1326
--- /dev/null
+++ b/libs/surfaceflinger/OrientationAnimation.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <limits.h>
+
+#include "LayerOrientationAnim.h"
+#include "OrientationAnimation.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+
+#include "DisplayHardware/DisplayHardware.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+OrientationAnimation::OrientationAnimation(const sp<SurfaceFlinger>& flinger)
+ : mFlinger(flinger), mLayerOrientationAnim(NULL), mState(DONE)
+{
+ // allocate a memory-dealer for this the first time
+ mTemporaryDealer = mFlinger->getSurfaceHeapManager()->createHeap(
+ ISurfaceComposer::eHardware);
+}
+
+OrientationAnimation::~OrientationAnimation()
+{
+}
+
+void OrientationAnimation::onOrientationChanged()
+{
+ if (mState == DONE)
+ mState = PREPARE;
+}
+
+void OrientationAnimation::onAnimationFinished()
+{
+ if (mState != DONE)
+ mState = FINISH;
+}
+
+bool OrientationAnimation::run_impl()
+{
+ bool skip_frame;
+ switch (mState) {
+ default:
+ case DONE:
+ skip_frame = done();
+ break;
+ case PREPARE:
+ skip_frame = prepare();
+ break;
+ case PHASE1:
+ skip_frame = phase1();
+ break;
+ case PHASE2:
+ skip_frame = phase2();
+ break;
+ case FINISH:
+ skip_frame = finished();
+ break;
+ }
+ return skip_frame;
+}
+
+bool OrientationAnimation::done()
+{
+ if (mFlinger->isFrozen()) {
+ // we are not allowed to draw, but pause a bit to make sure
+ // apps don't end up using the whole CPU, if they depend on
+ // surfaceflinger for synchronization.
+ usleep(8333); // 8.3ms ~ 120fps
+ return true;
+ }
+ return false;
+}
+
+bool OrientationAnimation::prepare()
+{
+ mState = PHASE1;
+
+ const GraphicPlane& plane(mFlinger->graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ const uint32_t w = hw.getWidth();
+ const uint32_t h = hw.getHeight();
+
+ LayerBitmap bitmap;
+ bitmap.init(mTemporaryDealer);
+ bitmap.setBits(w, h, 1, hw.getFormat());
+
+ LayerBitmap bitmapIn;
+ bitmapIn.init(mTemporaryDealer);
+ bitmapIn.setBits(w, h, 1, hw.getFormat());
+
+ copybit_image_t front;
+ bitmap.getBitmapSurface(&front);
+ hw.copyFrontToImage(front);
+
+ LayerOrientationAnim* l = new LayerOrientationAnim(
+ mFlinger.get(), 0, this, bitmap, bitmapIn);
+ l->initStates(w, h, 0);
+ l->setLayer(INT_MAX-1);
+ mFlinger->addLayer(l);
+ mLayerOrientationAnim = l;
+ return true;
+}
+
+bool OrientationAnimation::phase1()
+{
+ if (mFlinger->isFrozen() == false) {
+ // start phase 2
+ mState = PHASE2;
+ mLayerOrientationAnim->onOrientationCompleted();
+ mLayerOrientationAnim->invalidate();
+ return true;
+
+ }
+ mLayerOrientationAnim->invalidate();
+ return false;
+}
+
+bool OrientationAnimation::phase2()
+{
+ // do the 2nd phase of the animation
+ mLayerOrientationAnim->invalidate();
+ return false;
+}
+
+bool OrientationAnimation::finished()
+{
+ mState = DONE;
+ mFlinger->removeLayer(mLayerOrientationAnim);
+ mLayerOrientationAnim = NULL;
+ return true;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/OrientationAnimation.h b/libs/surfaceflinger/OrientationAnimation.h
new file mode 100644
index 0000000..ba33fce
--- /dev/null
+++ b/libs/surfaceflinger/OrientationAnimation.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_ORIENTATION_ANIMATION_H
+#define ANDROID_ORIENTATION_ANIMATION_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "SurfaceFlinger.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class SurfaceFlinger;
+class MemoryDealer;
+class LayerOrientationAnim;
+
+class OrientationAnimation
+{
+public:
+ OrientationAnimation(const sp<SurfaceFlinger>& flinger);
+ virtual ~OrientationAnimation();
+
+ void onOrientationChanged();
+ void onAnimationFinished();
+ inline bool run() {
+ if (LIKELY(mState == DONE))
+ return false;
+ return run_impl();
+ }
+
+private:
+ enum {
+ DONE = 0,
+ PREPARE,
+ PHASE1,
+ PHASE2,
+ FINISH
+ };
+
+ bool run_impl();
+ bool done();
+ bool prepare();
+ bool phase1();
+ bool phase2();
+ bool finished();
+
+ sp<SurfaceFlinger> mFlinger;
+ sp<MemoryDealer> mTemporaryDealer;
+ LayerOrientationAnim* mLayerOrientationAnim;
+ int mState;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_ORIENTATION_ANIMATION_H
diff --git a/libs/surfaceflinger/RFBServer.cpp b/libs/surfaceflinger/RFBServer.cpp
deleted file mode 100644
index c2c1989..0000000
--- a/libs/surfaceflinger/RFBServer.cpp
+++ /dev/null
@@ -1,722 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "RFBServer"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-
-#include <netinet/in.h>
-
-#include <cutils/sockets.h>
-
-#include <utils/Log.h>
-#include <ui/Rect.h>
-
-#ifdef HAVE_ANDROID_OS
-#include <linux/input.h>
-#endif
-
-#include "RFBServer.h"
-#include "SurfaceFlinger.h"
-
-/* BUG=773511: this is a temporary hack required while developing the new
- set of "clean kernel headers" for the Bionic C library. */
-#ifndef KEY_STAR
-#define KEY_STAR 227
-#endif
-#ifndef KEY_SHARP
-#define KEY_SHARP 228
-#endif
-#ifndef KEY_SOFT1
-#define KEY_SOFT1 229
-#endif
-#ifndef KEY_SOFT2
-#define KEY_SOFT2 230
-#endif
-#ifndef KEY_CENTER
-#define KEY_CENTER 232
-#endif
-
-// ----------------------------------------------------------------------------
-
-#define DEBUG_MSG 0
-
-// ----------------------------------------------------------------------------
-
-namespace android {
-
-const int VNC_PORT = 5900;
-
-RFBServer::RFBServer(uint32_t w, uint32_t h, android::PixelFormat format)
- : Thread(false), mFD(-1), mStatus(NO_INIT), mIoVec(0)
-{
- mFrameBuffer.version = sizeof(mFrameBuffer);
- mFrameBuffer.width = w;
- mFrameBuffer.height = h;
- mFrameBuffer.stride = w;
- mFrameBuffer.format = format;
- mFrameBuffer.data = 0;
-}
-
-RFBServer::~RFBServer()
-{
- if (mRobinThread != 0) {
- // ask the thread to exit first
- mRobinThread->exitAndWait();
- }
-
- free(mFrameBuffer.data);
-
- delete [] mIoVec;
-}
-
-void RFBServer::onFirstRef()
-{
- run("Batman");
-}
-
-status_t RFBServer::readyToRun()
-{
- LOGI("RFB server ready to run");
- return NO_ERROR;
-}
-
-bool RFBServer::threadLoop()
-{
- struct sockaddr addr;
- socklen_t alen;
- int serverfd = -1;
- int port = VNC_PORT;
-
- do {
- retry:
- if (serverfd < 0) {
- serverfd = socket_loopback_server(port, SOCK_STREAM);
- if (serverfd < 0) {
- if ((errno == EADDRINUSE) && (port < (VNC_PORT+10))) {
- LOGW("port %d already in use, trying %d", port, port+1);
- port++;
- goto retry;
- }
- LOGE("couldn't create socket, port=%d, error %d (%s)",
- port, errno, strerror(errno));
- sleep(1);
- break;
- }
- fcntl(serverfd, F_SETFD, FD_CLOEXEC);
- }
-
- alen = sizeof(addr);
- mFD = accept(serverfd, &addr, &alen);
-
- if (mFD < 0) {
- LOGE("couldn't accept(), error %d (%s)", errno, strerror(errno));
- // we could have run out of file descriptors, wait a bit and
- // try again.
- sleep(1);
- goto retry;
- }
- fcntl(mFD, F_SETFD, FD_CLOEXEC);
-
- // send protocol version and Authentication method
- mStatus = NO_ERROR;
- handshake(3, 3, Authentication::None);
-
- if (alive()) {
- // create the thread we use to send data to the client
- mRobinThread = new ServerThread(this);
- }
-
- while( alive() ) {
- // client message must be destroyed at each iteration
- // (most of the time this is a no-op)
- ClientMessage msg;
- waitForClientMessage(msg);
- if (alive()) {
- handleClientMessage(msg);
- }
- }
-
- } while( alive() );
-
- // free-up some resources
- if (mRobinThread != 0) {
- mRobinThread->exitAndWait();
- mRobinThread.clear();
- }
-
- free(mFrameBuffer.data);
- mFrameBuffer.data = 0;
-
- close(mFD);
- close(serverfd);
- mFD = -1;
-
- // we'll try again
- return true;
-}
-
-// ----------------------------------------------------------------------------
-
-RFBServer::ServerThread::ServerThread(const sp<RFBServer>& receiver)
- : Thread(false), mReceiver(receiver)
-{
- LOGD("RFB Server Thread created");
-}
-
-RFBServer::ServerThread::~ServerThread()
-{
- LOGD("RFB Server Thread destroyed");
-}
-
-void RFBServer::ServerThread::onFirstRef()
-{
- mUpdateBarrier.close();
- run("Robin");
-}
-
-status_t RFBServer::ServerThread::readyToRun()
-{
- return NO_ERROR;
-}
-
-void RFBServer::ServerThread::wake()
-{
- mUpdateBarrier.open();
-}
-
-void RFBServer::ServerThread::exitAndWait()
-{
- requestExit();
- mUpdateBarrier.open();
- requestExitAndWait();
-}
-
-bool RFBServer::ServerThread::threadLoop()
-{
- sp<RFBServer> receiver(mReceiver.promote());
- if (receiver == 0)
- return false;
-
- // wait for something to do
- mUpdateBarrier.wait();
-
- // we're asked to quit, abort everything
- if (exitPending())
- return false;
-
- mUpdateBarrier.close();
-
- // process updates
- receiver->sendFrameBufferUpdates();
- return !exitPending();
-}
-
-// ----------------------------------------------------------------------------
-
-void RFBServer::handshake(uint8_t major, uint8_t minor, uint32_t auth)
-{
- ProtocolVersion protocolVersion(major, minor);
- if( !write(protocolVersion) )
- return;
-
- if ( !read(protocolVersion) )
- return;
-
- int maj, min;
- if ( protocolVersion.decode(maj, min) != NO_ERROR ) {
- mStatus = -1;
- return;
- }
-
-#if DEBUG_MSG
- LOGD("client protocol string: <%s>", (char*)protocolVersion.payload());
- LOGD("client wants protocol version %d.%d\n", maj, min);
-#endif
-
- Authentication authentication(auth);
- if( !write(authentication) )
- return;
-
- ClientInitialization clientInit;
- if ( !read(clientInit) )
- return;
-
-#if DEBUG_MSG
- LOGD("client initialization: sharedFlags = %d\n", clientInit.sharedFlags());
-#endif
-
- ServerInitialization serverInit("Android RFB");
- ServerInitialization::Payload& message(serverInit.message());
- message.framebufferWidth = htons(mFrameBuffer.width);
- message.framebufferHeight = htons(mFrameBuffer.height);
- message.serverPixelFormat.bitsPerPixel = 16;
- message.serverPixelFormat.depth = 16;
- message.serverPixelFormat.bigEndianFlag = 0;
- message.serverPixelFormat.trueColorFlag = 1;
- message.serverPixelFormat.redMax = htons((1<<5)-1);
- message.serverPixelFormat.greenMax = htons((1<<6)-1);
- message.serverPixelFormat.blueMax = htons((1<<5)-1);
- message.serverPixelFormat.redShift = 11;
- message.serverPixelFormat.greenShift = 5;
- message.serverPixelFormat.blueShift = 0;
-
- mIoVec = new iovec[mFrameBuffer.height];
-
- write(serverInit);
-}
-
-void RFBServer::handleClientMessage(const ClientMessage& msg)
-{
- switch(msg.type()) {
- case SET_PIXEL_FORMAT:
- handleSetPixelFormat(msg.messages().setPixelFormat);
- break;
- case SET_ENCODINGS:
- handleSetEncodings(msg.messages().setEncodings);
- break;
- case FRAME_BUFFER_UPDATE_REQ:
- handleFrameBufferUpdateReq(msg.messages().frameBufferUpdateRequest);
- break;
- case KEY_EVENT:
- handleKeyEvent(msg.messages().keyEvent);
- break;
- }
-}
-
-void RFBServer::handleSetPixelFormat(const SetPixelFormat& msg)
-{
- if (!validatePixelFormat(msg.pixelFormat)) {
- LOGE("The builtin VNC server only supports the RGB 565 pixel format");
- LOGD("requested pixel format:");
- LOGD("bitsPerPixel: %d", msg.pixelFormat.bitsPerPixel);
- LOGD("depth: %d", msg.pixelFormat.depth);
- LOGD("bigEndianFlag: %d", msg.pixelFormat.bigEndianFlag);
- LOGD("trueColorFlag: %d", msg.pixelFormat.trueColorFlag);
- LOGD("redmax: %d", ntohs(msg.pixelFormat.redMax));
- LOGD("bluemax: %d", ntohs(msg.pixelFormat.greenMax));
- LOGD("greenmax: %d", ntohs(msg.pixelFormat.blueMax));
- LOGD("redshift: %d", msg.pixelFormat.redShift);
- LOGD("greenshift: %d", msg.pixelFormat.greenShift);
- LOGD("blueshift: %d", msg.pixelFormat.blueShift);
- mStatus = -1;
- }
-}
-
-bool RFBServer::validatePixelFormat(const PixelFormat& pf)
-{
- if ((pf.bitsPerPixel != 16) || (pf.depth != 16))
- return false;
-
- if (pf.bigEndianFlag || !pf.trueColorFlag)
- return false;
-
- if (ntohs(pf.redMax)!=0x1F ||
- ntohs(pf.greenMax)!=0x3F ||
- ntohs(pf.blueMax)!=0x1F) {
- return false;
- }
-
- if (pf.redShift!=11 || pf.greenShift!=5 || pf.blueShift!=0)
- return false;
-
- return true;
-}
-
-void RFBServer::handleSetEncodings(const SetEncodings& msg)
-{
- /* From the RFB specification:
- Sets the encoding types in which pixel data can be sent by the server.
- The order of the encoding types given in this message is a hint by the
- client as to its preference (the first encoding specified being most
- preferred). The server may or may not choose to make use of this hint.
- Pixel data may always be sent in raw encoding even if not specified
- explicitly here.
- */
-
- LOGW("SetEncodings received. Only RAW is supported.");
-}
-
-void RFBServer::handleFrameBufferUpdateReq(const FrameBufferUpdateRequest& msg)
-{
-#if DEBUG_MSG
- LOGD("handle FrameBufferUpdateRequest");
-#endif
-
- Rect r;
- r.left = ntohs(msg.x);
- r.top = ntohs(msg.y);
- r.right = r.left + ntohs(msg.width);
- r.bottom = r.top + ntohs(msg.height);
-
- Mutex::Autolock _l(mRegionLock);
- mClientRegionRequest.set(r);
- if (!msg.incremental)
- mDirtyRegion.orSelf(r);
-
- mRobinThread->wake();
-}
-
-void RFBServer::handleKeyEvent(const KeyEvent& msg)
-{
-#ifdef HAVE_ANDROID_OS
-
- int scancode = 0;
- int code = ntohl(msg.key);
-
- if (code>='0' && code<='9') {
- scancode = (code & 0xF) - 1;
- if (scancode<0) scancode += 10;
- scancode += KEY_1;
- } else if (code>=0xFF50 && code<=0xFF58) {
- static const uint16_t map[] =
- { KEY_HOME, KEY_LEFT, KEY_UP, KEY_RIGHT, KEY_DOWN,
- KEY_SOFT1, KEY_SOFT2, KEY_END, 0 };
- scancode = map[code & 0xF];
- } else if (code>=0xFFE1 && code<=0xFFEE) {
- static const uint16_t map[] =
- { KEY_LEFTSHIFT, KEY_LEFTSHIFT,
- KEY_COMPOSE, KEY_COMPOSE,
- KEY_LEFTSHIFT, KEY_LEFTSHIFT,
- 0,0,
- KEY_LEFTALT, KEY_RIGHTALT,
- 0, 0, 0, 0 };
- scancode = map[code & 0xF];
- } else if ((code>='A' && code<='Z') || (code>='a' && code<='z')) {
- static const uint16_t map[] = {
- KEY_A, KEY_B, KEY_C, KEY_D, KEY_E,
- KEY_F, KEY_G, KEY_H, KEY_I, KEY_J,
- KEY_K, KEY_L, KEY_M, KEY_N, KEY_O,
- KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T,
- KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z };
- scancode = map[(code & 0x5F) - 'A'];
- } else {
- switch (code) {
- case 0x0003: scancode = KEY_CENTER; break;
- case 0x0020: scancode = KEY_SPACE; break;
- case 0x0023: scancode = KEY_SHARP; break;
- case 0x0033: scancode = KEY_SHARP; break;
- case 0x002C: scancode = KEY_COMMA; break;
- case 0x003C: scancode = KEY_COMMA; break;
- case 0x002E: scancode = KEY_DOT; break;
- case 0x003E: scancode = KEY_DOT; break;
- case 0x002F: scancode = KEY_SLASH; break;
- case 0x003F: scancode = KEY_SLASH; break;
- case 0x0032: scancode = KEY_EMAIL; break;
- case 0x0040: scancode = KEY_EMAIL; break;
- case 0xFF08: scancode = KEY_BACKSPACE; break;
- case 0xFF1B: scancode = KEY_BACK; break;
- case 0xFF09: scancode = KEY_TAB; break;
- case 0xFF0D: scancode = KEY_ENTER; break;
- case 0x002A: scancode = KEY_STAR; break;
- case 0xFFBE: scancode = KEY_SEND; break; // F1
- case 0xFFBF: scancode = KEY_END; break; // F2
- case 0xFFC0: scancode = KEY_HOME; break; // F3
- case 0xFFC5: scancode = KEY_POWER; break; // F8
- }
- }
-
-#if DEBUG_MSG
- LOGD("handle KeyEvent 0x%08x, %d, scancode=%d\n", code, msg.downFlag, scancode);
-#endif
-
- if (scancode) {
- mEventInjector.injectKey(uint16_t(scancode),
- msg.downFlag ? EventInjector::DOWN : EventInjector::UP);
- }
-#endif
-}
-
-void RFBServer::waitForClientMessage(ClientMessage& msg)
-{
- if ( !read(msg.payload(), 1) )
- return;
-
- switch(msg.type()) {
-
- case SET_PIXEL_FORMAT:
- read(msg.payload(1), sizeof(SetPixelFormat)-1);
- break;
-
- case FIX_COLOUR_MAP_ENTRIES:
- mStatus = UNKNOWN_ERROR;
- return;
-
- case SET_ENCODINGS:
- {
- if ( !read(msg.payload(1), sizeof(SetEncodings)-1) )
- return;
-
- size_t size = ntohs( msg.messages().setEncodings.numberOfEncodings ) * 4;
- if (msg.resize(sizeof(SetEncodings) + size) != NO_ERROR) {
- mStatus = NO_MEMORY;
- return;
- }
-
- if ( !read(msg.payload(sizeof(SetEncodings)), size) )
- return;
-
- break;
- }
-
- case FRAME_BUFFER_UPDATE_REQ:
- read(msg.payload(1), sizeof(FrameBufferUpdateRequest)-1);
- break;
-
- case KEY_EVENT:
- read(msg.payload(1), sizeof(KeyEvent)-1);
- break;
-
- case POINTER_EVENT:
- read(msg.payload(1), sizeof(PointerEvent)-1);
- break;
-
- case CLIENT_CUT_TEXT:
- {
- if ( !read(msg.payload(1), sizeof(ClientCutText)-1) )
- return;
-
- size_t size = ntohl( msg.messages().clientCutText.length );
- if (msg.resize(sizeof(ClientCutText) + size) != NO_ERROR) {
- mStatus = NO_MEMORY;
- return;
- }
-
- if ( !read(msg.payload(sizeof(SetEncodings)), size) )
- return;
-
- break;
- }
-
- default:
- LOGE("Unknown Message %d", msg.type());
- mStatus = UNKNOWN_ERROR;
- return;
- }
-}
-
-// ----------------------------------------------------------------------------
-
-bool RFBServer::write(const Message& msg)
-{
- write(msg.payload(), msg.size());
- return alive();
-}
-
-bool RFBServer::read(Message& msg)
-{
- read(msg.payload(), msg.size());
- return alive();
-}
-
-bool RFBServer::write(const void* buffer, int size)
-{
- int wr = ::write(mFD, buffer, size);
- if (wr != size) {
- //LOGE("write(%d) error %d (%s)", size, wr, strerror(errno));
- mStatus = (wr == -1) ? errno : -1;
- }
- return alive();
-}
-
-bool RFBServer::read(void* buffer, int size)
-{
- int rd = ::read(mFD, buffer, size);
- if (rd != size) {
- //LOGE("read(%d) error %d (%s)", size, rd, strerror(errno));
- mStatus = (rd == -1) ? errno : -1;
- }
- return alive();
-}
-
-bool RFBServer::alive() const
-{
- return mStatus == 0;
-}
-
-bool RFBServer::isConnected() const
-{
- return alive();
-}
-
-// ----------------------------------------------------------------------------
-
-void RFBServer::frameBufferUpdated(const GGLSurface& front, const Region& reg)
-{
- Mutex::Autolock _l(mRegionLock);
-
- // update dirty region
- mDirtyRegion.orSelf(reg);
-
- // remember the front-buffer
- mFrontBuffer = front;
-
- // The client has not requested anything, don't do anything more
- if (mClientRegionRequest.isEmpty())
- return;
-
- // wake the sending thread up
- mRobinThread->wake();
-}
-
-void RFBServer::sendFrameBufferUpdates()
-{
- Vector<Rect> rects;
- size_t countRects;
- GGLSurface fb;
-
- { // Scope for the lock
- Mutex::Autolock _l(mRegionLock);
- if (mFrontBuffer.data == 0)
- return;
-
- const Region reg( mDirtyRegion.intersect(mClientRegionRequest) );
- if (reg.isEmpty())
- return;
-
- mDirtyRegion.subtractSelf(reg);
- countRects = reg.rects(rects);
-
- // copy the frame-buffer so we can stay responsive
- size_t bytesPerPix = bytesPerPixel(mFrameBuffer.format);
- size_t bpr = mFrameBuffer.stride * bytesPerPix;
- if (mFrameBuffer.data == 0) {
- mFrameBuffer.data = (GGLubyte*)malloc(bpr * mFrameBuffer.height);
- if (mFrameBuffer.data == 0)
- return;
- }
-
- memcpy(mFrameBuffer.data, mFrontBuffer.data, bpr*mFrameBuffer.height);
- fb = mFrameBuffer;
- }
-
- FrameBufferUpdate msgHeader;
- msgHeader.type = 0;
- msgHeader.numberOfRectangles = htons(countRects);
- write(&msgHeader, sizeof(msgHeader));
-
- Rectangle rectangle;
- for (size_t i=0 ; i<countRects ; i++) {
- const Rect& r = rects[i];
- rectangle.x = htons( r.left );
- rectangle.y = htons( r.top );
- rectangle.w = htons( r.width() );
- rectangle.h = htons( r.height() );
- rectangle.encoding = htons( SetEncodings::Raw );
- write(&rectangle, sizeof(rectangle));
- size_t h = r.height();
- size_t w = r.width();
- size_t bytesPerPix = bytesPerPixel(fb.format);
- size_t bpr = fb.stride * bytesPerPix;
- size_t bytes = w * bytesPerPix;
- size_t offset = (r.top * bpr) + (r.left * bytesPerPix);
- uint8_t* src = static_cast<uint8_t*>(fb.data) + offset;
- iovec* iov = mIoVec;
- while (h--) {
- iov->iov_base = src;
- iov->iov_len = bytes;
- src += bpr;
- iov++;
- }
- size_t iovcnt = iov - mIoVec;
- int wr = ::writev(mFD, mIoVec, iovcnt);
- if (wr < 0) {
- //LOGE("write(%d) error %d (%s)", size, wr, strerror(errno));
- mStatus = errno;
- }
- }
-}
-
-// ----------------------------------------------------------------------------
-
-RFBServer::Message::Message(size_t size)
- : mSize(size), mAllocatedSize(size)
-{
- mPayload = malloc(size);
-}
-
-RFBServer::Message::Message(void* payload, size_t size)
- : mPayload(payload), mSize(size), mAllocatedSize(0)
-{
-}
-
-RFBServer::Message::~Message()
-{
- if (mAllocatedSize)
- free(mPayload);
-}
-
-status_t RFBServer::Message::resize(size_t size)
-{
- if (size > mAllocatedSize) {
- void* newp;
- if (mAllocatedSize) {
- newp = realloc(mPayload, size);
- if (!newp) return NO_MEMORY;
- } else {
- newp = malloc(size);
- if (!newp) return NO_MEMORY;
- memcpy(newp, mPayload, mSize);
- mAllocatedSize = size;
- }
- mPayload = newp;
- }
- mSize = size;
- return NO_ERROR;
-}
-
-// ----------------------------------------------------------------------------
-
-RFBServer::EventInjector::EventInjector()
- : mFD(-1)
-{
-}
-
-RFBServer::EventInjector::~EventInjector()
-{
-}
-
-void RFBServer::EventInjector::injectKey(uint16_t code, uint16_t value)
-{
-#ifdef HAVE_ANDROID_OS
- // XXX: we need to open the right event device
- int version;
- mFD = open("/dev/input/event0", O_RDWR);
- ioctl(mFD, EVIOCGVERSION, &version);
-
- input_event ev;
- memset(&ev, 0, sizeof(ev));
- ev.type = EV_KEY;
- ev.code = code;
- ev.value = value;
- ::write(mFD, &ev, sizeof(ev));
-
- close(mFD);
- mFD = -1;
-#endif
-}
-
-
-}; // namespace android
-
diff --git a/libs/surfaceflinger/RFBServer.h b/libs/surfaceflinger/RFBServer.h
deleted file mode 100644
index 420912e..0000000
--- a/libs/surfaceflinger/RFBServer.h
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_RFB_SERVER_H
-#define ANDROID_RFB_SERVER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-
-#include <utils/Errors.h>
-#include <utils/threads.h>
-#include <ui/Region.h>
-#include <ui/PixelFormat.h>
-
-#include <pixelflinger/pixelflinger.h>
-
-#include "Barrier.h"
-
-namespace android {
-
-class SurfaceFlinger;
-
-class RFBServer : public Thread
-{
-public:
- RFBServer(uint32_t w, uint32_t h, android::PixelFormat format);
- virtual ~RFBServer();
-
- void frameBufferUpdated(const GGLSurface& front, const Region& reg);
- bool isConnected() const;
-
-private:
- typedef uint8_t card8;
- typedef uint16_t card16;
- typedef uint32_t card32;
-
- struct Message {
- Message(size_t size);
- virtual ~Message();
- void* payload(int offset=0) {
- return static_cast<char*>(mPayload)+offset;
- }
- void const * payload(int offset=0) const {
- return static_cast<char const *>(mPayload)+offset;
- }
- size_t size() const { return mSize; }
- protected:
- Message(void* payload, size_t size);
- status_t resize(size_t size);
- private:
- void* mPayload;
- size_t mSize;
- size_t mAllocatedSize;
- };
-
- struct ProtocolVersion : public Message {
- ProtocolVersion(uint8_t major, uint8_t minor)
- : Message(&messageData, 12) {
- char* p = static_cast<char*>(payload());
- snprintf(p, 13, "RFB %03u.%03u%c", major, minor, 0xA);
- }
- status_t decode(int& maj, int& min) {
- char* p = static_cast<char*>(payload());
- int n = sscanf(p, "RFB %03u.%03u", &maj, &min);
- return (n == 2) ? NO_ERROR : NOT_ENOUGH_DATA;
- }
- private:
- char messageData[12+1];
- };
-
- struct Authentication : public Message {
- enum { Failed=0, None=1, Vnc=2 };
- Authentication(int auth) : Message(&messageData, 4) {
- *static_cast<card32*>(payload()) = htonl(auth);
- }
- private:
- card32 messageData;
- };
-
- struct ClientInitialization : public Message {
- ClientInitialization() : Message(&messageData, 1) { }
- int sharedFlags() {
- return messageData;
- }
- private:
- card8 messageData;
- };
-
- struct PixelFormat {
- card8 bitsPerPixel;
- card8 depth;
- card8 bigEndianFlag;
- card8 trueColorFlag;
- card16 redMax;
- card16 greenMax;
- card16 blueMax;
- card8 redShift;
- card8 greenShift;
- card8 blueShift;
- uint8_t padding[3];
- } __attribute__((packed));
-
- struct ServerInitialization : public Message {
- ServerInitialization(char const * name)
- : Message(sizeof(Payload) + strlen(name))
- {
- const size_t nameLength = size() - sizeof(Payload);
- message().nameLength = htonl(nameLength);
- memcpy((char*)message().nameString, name,nameLength);
- }
- struct Payload {
- card16 framebufferWidth;
- card16 framebufferHeight;
- PixelFormat serverPixelFormat;
- card32 nameLength;
- card8 nameString[0];
- } __attribute__((packed));
- Payload& message() {
- return *static_cast<Payload*>(payload());
- }
- };
-
- // client messages...
-
- struct SetPixelFormat {
- card8 type;
- uint8_t padding[3];
- PixelFormat pixelFormat;
- } __attribute__((packed));
-
- struct SetEncodings {
- enum { Raw=0, CoR=1, RRE=2, CoRRE=4, Hextile=5 };
- card8 type;
- uint8_t padding;
- card16 numberOfEncodings;
- card32 encodings[0];
- } __attribute__((packed));
-
- struct FrameBufferUpdateRequest {
- card8 type;
- card8 incremental;
- card16 x;
- card16 y;
- card16 width;
- card16 height;
- } __attribute__((packed));
-
- struct KeyEvent {
- card8 type;
- card8 downFlag;
- uint8_t padding[2];
- card32 key;
- } __attribute__((packed));
-
- struct PointerEvent {
- card8 type;
- card8 buttonMask;
- card16 x;
- card16 y;
- } __attribute__((packed));
-
- struct ClientCutText {
- card8 type;
- uint8_t padding[3];
- card32 length;
- card8 text[0];
- } __attribute__((packed));
-
- union ClientMessages {
- card8 type;
- SetPixelFormat setPixelFormat;
- SetEncodings setEncodings;
- FrameBufferUpdateRequest frameBufferUpdateRequest;
- KeyEvent keyEvent;
- PointerEvent pointerEvent;
- ClientCutText clientCutText;
- };
-
- struct Rectangle {
- card16 x;
- card16 y;
- card16 w;
- card16 h;
- card32 encoding;
- } __attribute__((packed));
-
- struct FrameBufferUpdate {
- card8 type;
- uint8_t padding;
- card16 numberOfRectangles;
- Rectangle rectangles[0];
- } __attribute__((packed));
-
- enum {
- SET_PIXEL_FORMAT = 0,
- FIX_COLOUR_MAP_ENTRIES = 1,
- SET_ENCODINGS = 2,
- FRAME_BUFFER_UPDATE_REQ = 3,
- KEY_EVENT = 4,
- POINTER_EVENT = 5,
- CLIENT_CUT_TEXT = 6,
- };
-
- struct ClientMessage : public Message {
- ClientMessage()
- : Message(&messageData, sizeof(messageData)) {
- }
- const ClientMessages& messages() const {
- return *static_cast<ClientMessages const *>(payload());
- }
- const int type() const {
- return messages().type;
- }
- status_t resize(size_t size) {
- return Message::resize(size);
- }
-
- ClientMessages messageData;
- };
-
-
- class ServerThread : public Thread
- {
- friend class RFBServer;
- public:
- ServerThread(const sp<RFBServer>& receiver);
- virtual ~ServerThread();
- void wake();
- void exitAndWait();
- private:
- virtual bool threadLoop();
- virtual status_t readyToRun();
- virtual void onFirstRef();
- wp<RFBServer> mReceiver;
- bool (RFBServer::*mAction)();
- Barrier mUpdateBarrier;
- };
-
- class EventInjector {
- public:
- enum { UP=0, DOWN=1 };
- EventInjector();
- ~EventInjector();
- void injectKey(uint16_t code, uint16_t value);
- private:
- struct input_event {
- struct timeval time;
- uint16_t type;
- uint16_t code;
- uint32_t value;
- };
- int mFD;
- };
-
- void handshake(uint8_t major, uint8_t minor, uint32_t auth);
- void waitForClientMessage(ClientMessage& msg);
- void handleClientMessage(const ClientMessage& msg);
- void handleSetPixelFormat(const SetPixelFormat& msg);
- void handleSetEncodings(const SetEncodings& msg);
- void handleFrameBufferUpdateReq(const FrameBufferUpdateRequest& msg);
- void handleKeyEvent(const KeyEvent& msg);
- void sendFrameBufferUpdates();
-
- bool validatePixelFormat(const PixelFormat& pf);
- bool alive() const;
- bool write(const Message& msg);
- bool read(Message& msg);
-
- bool write(const void* buffer, int size);
- bool read(void* buffer, int size);
-
- virtual bool threadLoop();
- virtual status_t readyToRun();
- virtual void onFirstRef();
-
- sp<ServerThread> mRobinThread;
-
- int mFD;
- int mStatus;
- iovec* mIoVec;
-
- EventInjector mEventInjector;
-
- Mutex mRegionLock;
- // This is the region requested by the client since the last
- // time we updated it
- Region mClientRegionRequest;
- // This is the region of the screen that needs to be sent to the
- // client since the last time we updated it.
- // Typically this is the dirty region, but not necessarily, for
- // instance if the client asked for a non incremental update.
- Region mDirtyRegion;
-
- GGLSurface mFrameBuffer;
- GGLSurface mFrontBuffer;
-};
-
-}; // namespace android
-
-#endif // ANDROID_RFB_SERVER_H
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 554e8e7..242d026 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -53,20 +53,15 @@
#include "LayerBuffer.h"
#include "LayerDim.h"
#include "LayerBitmap.h"
-#include "LayerScreenshot.h"
+#include "LayerOrientationAnim.h"
+#include "OrientationAnimation.h"
#include "SurfaceFlinger.h"
-#include "RFBServer.h"
#include "VRamHeap.h"
#include "DisplayHardware/DisplayHardware.h"
#include "GPUHardware/GPUHardware.h"
-// the VNC server even on local ports presents a significant
-// thread as it can allow an application to control and "see" other
-// applications, de-facto bypassing security permissions.
-#define ENABLE_VNC_SERVER 0
-
#define DISPLAY_COUNT 1
namespace android {
@@ -185,6 +180,7 @@
mDeferReleaseConsole(false),
mFreezeDisplay(false),
mFreezeCount(0),
+ mFreezeDisplayTime(0),
mDebugRegion(0),
mDebugCpu(0),
mDebugFps(0),
@@ -225,6 +221,7 @@
SurfaceFlinger::~SurfaceFlinger()
{
glDeleteTextures(1, &mWormholeTexName);
+ delete mOrientationAnimation;
}
copybit_device_t* SurfaceFlinger::getBlitEngine() const
@@ -448,6 +445,8 @@
* We're now ready to accept clients...
*/
+ mOrientationAnimation = new OrientationAnimation(this);
+
// start CPU gauge display
if (mDebugCpu)
mCpuGauge = new CPUGauge(this, ms2ns(500));
@@ -456,9 +455,6 @@
if (mDebugNoBootAnimation == false)
mBootAnimation = new BootAnimation(this);
- if (ENABLE_VNC_SERVER)
- mRFBServer = new RFBServer(w, h, f);
-
return NO_ERROR;
}
@@ -472,17 +468,25 @@
{
// wait for something to do
if (UNLIKELY(isFrozen())) {
- // wait 2 seconds
- int err = mSyncObject.wait(ms2ns(3000));
+ // wait 5 seconds
+ const nsecs_t freezeDisplayTimeout = ms2ns(5000);
+ const nsecs_t now = systemTime();
+ if (mFreezeDisplayTime == 0) {
+ mFreezeDisplayTime = now;
+ }
+ nsecs_t waitTime = freezeDisplayTimeout - (now - mFreezeDisplayTime);
+ int err = (waitTime > 0) ? mSyncObject.wait(waitTime) : TIMED_OUT;
if (err != NO_ERROR) {
if (isFrozen()) {
// we timed out and are still frozen
LOGW("timeout expired mFreezeDisplay=%d, mFreezeCount=%d",
mFreezeDisplay, mFreezeCount);
mFreezeCount = 0;
+ mFreezeDisplay = false;
}
}
} else {
+ mFreezeDisplayTime = 0;
mSyncObject.wait();
}
}
@@ -556,11 +560,8 @@
void SurfaceFlinger::postFramebuffer()
{
- if (UNLIKELY(isFrozen())) {
- // we are not allowed to draw, but pause a bit to make sure
- // apps don't end up using the whole CPU, if they depend on
- // surfaceflinger for synchronization.
- usleep(8333); // 8.3ms ~ 120fps
+ const bool skip = mOrientationAnimation->run();
+ if (UNLIKELY(skip)) {
return;
}
@@ -571,18 +572,6 @@
debugShowFPS();
}
- if (UNLIKELY(ENABLE_VNC_SERVER &&
- mRFBServer!=0 && mRFBServer->isConnected())) {
- if (!mSecureFrameBuffer) {
- GGLSurface fb;
- // backbufer, is going to become the front buffer really soon
- hw.getDisplaySurface(&fb);
- if (LIKELY(fb.data != 0)) {
- mRFBServer->frameBufferUpdated(fb, mInvalidRegion);
- }
- }
- }
-
hw.flip(mInvalidRegion);
mInvalidRegion.clear();
@@ -685,18 +674,13 @@
mVisibleRegionsDirty = true;
mDirtyRegion.set(hw.bounds());
+
+ mOrientationAnimation->onOrientationChanged();
}
if (mCurrentState.freezeDisplay != mDrawingState.freezeDisplay) {
// freezing or unfreezing the display -> trigger animation if needed
mFreezeDisplay = mCurrentState.freezeDisplay;
- const nsecs_t now = systemTime();
- if (mFreezeDisplay) {
- mFreezeDisplayTime = now;
- } else {
- //LOGD("Screen was frozen for %llu us",
- // ns2us(now-mFreezeDisplayTime));
- }
}
// some layers might have been removed, so
@@ -875,19 +859,9 @@
uint32_t flags = hw.getFlags();
if (flags & DisplayHardware::BUFFER_PRESERVED) {
- if (flags & DisplayHardware::COPY_BACK_EXTENSION) {
- // yay. nothing to do here.
- } else {
- if (flags & DisplayHardware::UPDATE_ON_DEMAND) {
- // we need to fully redraw the part that will be updated
- mDirtyRegion.set(mInvalidRegion.bounds());
- } else {
- // TODO: we only need te redraw the part that had been drawn
- // the round before and is not drawn now
- }
- }
+ // here we assume DisplayHardware::flip()'s implementation
+ // performs the copy-back optimization.
} else {
- // COPY_BACK_EXTENSION makes no sense here
if (flags & DisplayHardware::UPDATE_ON_DEMAND) {
// we need to fully redraw the part that will be updated
mDirtyRegion.set(mInvalidRegion.bounds());
@@ -1077,6 +1051,29 @@
// XXX: mFPS has the value we want
}
+status_t SurfaceFlinger::addLayer(LayerBase* layer)
+{
+ Mutex::Autolock _l(mStateLock);
+ addLayer_l(layer);
+ setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::removeLayer(LayerBase* layer)
+{
+ Mutex::Autolock _l(mStateLock);
+ removeLayer_l(layer);
+ setTransactionFlags(eTransactionNeeded);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::invalidateLayerVisibility(LayerBase* layer)
+{
+ layer->forceVisibilityTransaction();
+ setTransactionFlags(eTraversalNeeded);
+ return NO_ERROR;
+}
+
status_t SurfaceFlinger::addLayer_l(LayerBase* layer)
{
ssize_t i = mCurrentState.layersSortedByZ.add(
@@ -1555,55 +1552,17 @@
status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
- if (code == 1012) {
- // take screen-shot of the front buffer
- if (UNLIKELY(checkCallingPermission(
- String16("android.permission.READ_FRAME_BUFFER")) == false))
- { // not allowed
- LOGE("Permission Denial: "
- "can't take screenshots from pid=%d, uid=%d\n",
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid());
- return PERMISSION_DENIED;
- }
-
- if (UNLIKELY(mSecureFrameBuffer)) {
- LOGE("A secure window is on screen: "
- "can't take screenshots from pid=%d, uid=%d\n",
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid());
- return PERMISSION_DENIED;
- }
-
- LOGI("Taking a screenshot...");
-
- LayerScreenshot* l = new LayerScreenshot(this, 0);
-
- Mutex::Autolock _l(mStateLock);
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
- l->initStates(hw.getWidth(), hw.getHeight(), 0);
- l->setLayer(INT_MAX);
-
- addLayer_l(l);
- setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
-
- l->takeScreenshot(mStateLock, reply);
-
- removeLayer_l(l);
- setTransactionFlags(eTransactionNeeded);
- return NO_ERROR;
- } else {
- // HARDWARE_TEST stuff...
- if (UNLIKELY(checkCallingPermission(
- String16("android.permission.HARDWARE_TEST")) == false))
- { // not allowed
- LOGE("Permission Denial: pid=%d, uid=%d\n",
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid());
- return PERMISSION_DENIED;
- }
- int n;
- switch (code) {
+ // HARDWARE_TEST stuff...
+ if (UNLIKELY(checkCallingPermission(
+ String16("android.permission.HARDWARE_TEST")) == false))
+ { // not allowed
+ LOGE("Permission Denial: pid=%d, uid=%d\n",
+ IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid());
+ return PERMISSION_DENIED;
+ }
+ int n;
+ switch (code) {
case 1000: // SHOW_CPU
n = data.readInt32();
mDebugCpu = n ? 1 : 0;
@@ -1636,8 +1595,8 @@
const DisplayHardware& hw(graphicPlane(0).displayHardware());
mDirtyRegion.set(hw.bounds()); // careful that's not thread-safe
signalEvent();
- }
- return NO_ERROR;
+ }
+ return NO_ERROR;
case 1005: // ask GPU revoke
mGPU->friendlyRevoke();
return NO_ERROR;
@@ -1653,13 +1612,12 @@
reply->writeInt32(mDebugRegion);
reply->writeInt32(mDebugBackground);
return NO_ERROR;
- case 1013: { // screenshot
+ case 1013: {
Mutex::Autolock _l(mStateLock);
const DisplayHardware& hw(graphicPlane(0).displayHardware());
reply->writeInt32(hw.getPageFlipCount());
}
return NO_ERROR;
- }
}
}
return err;
@@ -1813,10 +1771,33 @@
mGlobalTransform = mOrientationTransform * mTransform;
}
+status_t GraphicPlane::orientationToTransfrom(
+ int orientation, int w, int h, Transform* tr)
+{
+ float a, b, c, d, x, y;
+ switch (orientation) {
+ case ISurfaceComposer::eOrientationDefault:
+ a=1; b=0; c=0; d=1; x=0; y=0;
+ break;
+ case ISurfaceComposer::eOrientation90:
+ a=0; b=-1; c=1; d=0; x=w; y=0;
+ break;
+ case ISurfaceComposer::eOrientation180:
+ a=-1; b=0; c=0; d=-1; x=w; y=h;
+ break;
+ case ISurfaceComposer::eOrientation270:
+ a=0; b=1; c=-1; d=0; x=0; y=h;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+ tr->set(a, b, c, d);
+ tr->set(x, y);
+ return NO_ERROR;
+}
+
status_t GraphicPlane::setOrientation(int orientation)
{
- float a, b, c, d, x, y;
-
const DisplayHardware& hw(displayHardware());
const float w = hw.getWidth();
const float h = hw.getHeight();
@@ -1830,30 +1811,21 @@
// If the rotation can be handled in hardware, this is where
// the magic should happen.
-
- switch (orientation) {
- case ISurfaceComposer::eOrientation90:
- a=0; b=-1; c=1; d=0; x=w; y=0;
- break;
- case ISurfaceComposer::eOrientation180:
- a=-1; b=0; c=0; d=-1; x=w; y=h;
- break;
- case ISurfaceComposer::eOrientation270:
- a=0; b=1; c=-1; d=0; x=0; y=h;
- break;
- case 42: {
+ 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);
- } break;
- default:
- return BAD_VALUE;
+ mOrientationTransform.set(a, b, c, d);
+ mOrientationTransform.set(x, y);
+ } else {
+ GraphicPlane::orientationToTransfrom(orientation, w, h,
+ &mOrientationTransform);
}
- mOrientationTransform.set(a, b, c, d);
- mOrientationTransform.set(x, y);
+
mGlobalTransform = mOrientationTransform * mTransform;
return NO_ERROR;
}
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index a242f1a..f7d7764 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -35,11 +35,11 @@
#include <private/ui/LayerState.h>
#include <private/ui/SurfaceFlingerSynchro.h>
+#include "Barrier.h"
+#include "BootAnimation.h"
+#include "CPUGauge.h"
#include "Layer.h"
#include "Tokenizer.h"
-#include "CPUGauge.h"
-#include "BootAnimation.h"
-#include "Barrier.h"
struct copybit_device_t;
struct overlay_device_t;
@@ -48,16 +48,17 @@
// ---------------------------------------------------------------------------
-class BClient;
class Client;
+class BClient;
class DisplayHardware;
+class FreezeLock;
class GPUHardwareInterface;
class IGPUCallback;
class Layer;
class LayerBuffer;
-class RFBServer;
+class LayerOrientationAnim;
+class OrientationAnimation;
class SurfaceHeapManager;
-class FreezeLock;
typedef int32_t ClientID;
@@ -110,6 +111,8 @@
class GraphicPlane
{
public:
+ static status_t orientationToTransfrom(int orientation, int w, int h,
+ Transform* tr);
GraphicPlane();
~GraphicPlane();
@@ -181,7 +184,12 @@
copybit_device_t* getBlitEngine() const;
overlay_control_device_t* getOverlayEngine() const;
+
+ status_t removeLayer(LayerBase* layer);
+ status_t addLayer(LayerBase* layer);
+ status_t invalidateLayerVisibility(LayerBase* layer);
+
private:
friend class BClient;
friend class LayerBase;
@@ -337,7 +345,6 @@
sp<GPUHardwareInterface> mGPU;
GLuint mWormholeTexName;
sp<BootAnimation> mBootAnimation;
- sp<RFBServer> mRFBServer;
nsecs_t mBootTime;
// Can only accessed from the main thread, these members
@@ -352,6 +359,8 @@
bool mFreezeDisplay;
int32_t mFreezeCount;
nsecs_t mFreezeDisplayTime;
+ friend class OrientationAnimation;
+ OrientationAnimation* mOrientationAnimation;
// access protected by mDebugLock
mutable Mutex mDebugLock;
diff --git a/libs/surfaceflinger/VRamHeap.cpp b/libs/surfaceflinger/VRamHeap.cpp
index 77bc576..0ccd71f 100644
--- a/libs/surfaceflinger/VRamHeap.cpp
+++ b/libs/surfaceflinger/VRamHeap.cpp
@@ -35,8 +35,6 @@
#include <utils/MemoryHeapPmem.h>
#include <utils/MemoryHeapBase.h>
-#include <GLES/eglnatives.h>
-
#include "GPUHardware/GPUHardware.h"
#include "SurfaceFlinger.h"
#include "VRamHeap.h"
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index 50c6008..b3cbda1 100644
--- a/libs/ui/Camera.cpp
+++ b/libs/ui/Camera.cpp
@@ -84,8 +84,10 @@
mRawCallbackCookie = 0;
mJpegCallback = 0;
mJpegCallbackCookie = 0;
- mFrameCallback = 0;
- mFrameCallbackCookie = 0;
+ mPreviewCallback = 0;
+ mPreviewCallbackCookie = 0;
+ mRecordingCallback = 0;
+ mRecordingCallbackCookie = 0;
mErrorCallback = 0;
mErrorCallbackCookie = 0;
mAutoFocusCallback = 0;
@@ -108,6 +110,8 @@
if (c->mCamera != 0) {
c->mCamera->asBinder()->linkToDeath(c);
c->mStatus = NO_ERROR;
+ } else {
+ c.clear();
}
return c;
}
@@ -184,6 +188,15 @@
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()
{
@@ -193,6 +206,24 @@
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()
{
@@ -202,6 +233,15 @@
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");
@@ -266,14 +306,21 @@
mJpegCallbackCookie = cookie;
}
-void Camera::setFrameCallback(frame_callback cb, void *cookie, int frame_callback_flag)
+void Camera::setPreviewCallback(frame_callback cb, void *cookie, int flag)
{
- LOGV("setFrameCallback");
- mFrameCallback = cb;
- mFrameCallbackCookie = cookie;
+ LOGV("setPreviewCallback");
+ mPreviewCallback = cb;
+ mPreviewCallbackCookie = cookie;
sp <ICamera> c = mCamera;
if (c == 0) return;
- mCamera->setFrameCallbackFlag(frame_callback_flag);
+ mCamera->setPreviewCallbackFlag(flag);
+}
+
+void Camera::setRecordingCallback(frame_callback cb, void *cookie)
+{
+ LOGV("setRecordingCallback");
+ mRecordingCallback = cb;
+ mRecordingCallbackCookie = cookie;
}
void Camera::setErrorCallback(error_callback cb, void *cookie)
@@ -316,12 +363,21 @@
}
}
-// callback from camera service when video frame is ready
-void Camera::frameCallback(const sp<IMemory>& frame)
+// callback from camera service when preview frame is ready
+void Camera::previewCallback(const sp<IMemory>& frame)
{
LOGV("frameCallback");
- if (mFrameCallback) {
- mFrameCallback(frame, mFrameCallbackCookie);
+ if (mPreviewCallback) {
+ mPreviewCallback(frame, mPreviewCallbackCookie);
+ }
+}
+
+// callback from camera service when a recording frame is ready
+void Camera::recordingCallback(const sp<IMemory>& frame)
+{
+ LOGV("recordingCallback");
+ if (mRecordingCallback) {
+ mRecordingCallback(frame, mRecordingCallbackCookie);
}
}
diff --git a/libs/ui/CameraParameters.cpp b/libs/ui/CameraParameters.cpp
index 7ca77bb..6c25836 100644
--- a/libs/ui/CameraParameters.cpp
+++ b/libs/ui/CameraParameters.cpp
@@ -24,6 +24,9 @@
namespace android {
+static const char* portrait = "portrait";
+static const char* landscape = "landscape";
+
CameraParameters::CameraParameters()
: mMap()
{
@@ -182,6 +185,23 @@
set("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("preview-format", portrait);
+ } else {
+ set("preview-format", landscape);
+ }
+}
+
const char *CameraParameters::getPreviewFormat() const
{
return get("preview-format");
diff --git a/libs/ui/EGLDisplaySurface.cpp b/libs/ui/EGLDisplaySurface.cpp
index 44258a8..d06c98b 100644
--- a/libs/ui/EGLDisplaySurface.cpp
+++ b/libs/ui/EGLDisplaySurface.cpp
@@ -42,7 +42,7 @@
#include <linux/msm_mdp.h>
#endif
-#include <GLES/egl.h>
+#include <EGL/egl.h>
#include <pixelflinger/format.h>
@@ -71,8 +71,6 @@
egl_native_window_t::incRef = &EGLDisplaySurface::hook_incRef;
egl_native_window_t::decRef = &EGLDisplaySurface::hook_decRef;
egl_native_window_t::swapBuffers = &EGLDisplaySurface::hook_swapBuffers;
- egl_native_window_t::setSwapRectangle = &EGLDisplaySurface::hook_setSwapRectangle;
- egl_native_window_t::nextBuffer = &EGLDisplaySurface::hook_nextBuffer;
egl_native_window_t::connect = 0;
egl_native_window_t::disconnect = 0;
@@ -136,15 +134,6 @@
EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
return that->swapBuffers();
}
-uint32_t EGLDisplaySurface::hook_nextBuffer(NativeWindowType window) {
- EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
- return that->nextBuffer();
-}
-void EGLDisplaySurface::hook_setSwapRectangle(NativeWindowType window,
- int l, int t, int w, int h) {
- EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
- that->setSwapRectangle(l, t, w, h);
-}
void EGLDisplaySurface::setSwapRectangle(int l, int t, int w, int h)
{
@@ -249,15 +238,6 @@
return mPageFlipCount;
}
-uint32_t EGLDisplaySurface::nextBuffer()
-{
- // update the address of the buffer to draw to next
- const GGLSurface& buffer = mFb[mIndex];
- egl_native_window_t::offset =
- intptr_t(buffer.data) - egl_native_window_t::base;
- return 0;
-}
-
void EGLDisplaySurface::copyFrontToBack(const Region& copyback)
{
#if HAVE_ANDROID_OS
@@ -318,6 +298,59 @@
}
}
+void EGLDisplaySurface::copyFrontToImage(const copybit_image_t& dst)
+{
+#if HAVE_ANDROID_OS
+ if (mBlitEngine) {
+ copybit_image_t src = {
+ w: egl_native_window_t::stride,
+ h: egl_native_window_t::height,
+ format: egl_native_window_t::format,
+ offset: mFb[mIndex].data - mFb[0].data,
+ base: (void*)egl_native_window_t::base,
+ fd: egl_native_window_t::fd
+ };
+ region_iterator it(Region(Rect(
+ egl_native_window_t::width, egl_native_window_t::height)));
+ mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
+ } else
+#endif
+ {
+ uint8_t* const screen_src = mFb[ mIndex].data;
+ const size_t bpp = bytesPerPixel(egl_native_window_t::format);
+ const size_t bpr = egl_native_window_t::stride * bpp;
+ memcpy((char*)dst.base + dst.offset, screen_src,
+ bpr*egl_native_window_t::height);
+ }
+}
+
+void EGLDisplaySurface::copyBackToImage(const copybit_image_t& dst)
+{
+#if HAVE_ANDROID_OS
+ if (mBlitEngine) {
+ copybit_image_t src = {
+ w: egl_native_window_t::stride,
+ h: egl_native_window_t::height,
+ format: egl_native_window_t::format,
+ offset: mFb[1-mIndex].data - mFb[0].data,
+ base: (void*)egl_native_window_t::base,
+ fd: egl_native_window_t::fd
+ };
+ region_iterator it(Region(Rect(
+ egl_native_window_t::width, egl_native_window_t::height)));
+ mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
+ } else
+#endif
+ {
+ uint8_t* const screen_src = mFb[1-mIndex].data;
+ const size_t bpp = bytesPerPixel(egl_native_window_t::format);
+ const size_t bpr = egl_native_window_t::stride * bpp;
+ memcpy((char*)dst.base + dst.offset, screen_src,
+ bpr*egl_native_window_t::height);
+ }
+}
+
+
status_t EGLDisplaySurface::mapFrameBuffer()
{
char const * const device_template[] = {
diff --git a/libs/ui/EGLNativeWindowSurface.cpp b/libs/ui/EGLNativeWindowSurface.cpp
index d55fb70..f1071cf 100644
--- a/libs/ui/EGLNativeWindowSurface.cpp
+++ b/libs/ui/EGLNativeWindowSurface.cpp
@@ -28,7 +28,7 @@
#include <ui/DisplayInfo.h>
#include <ui/Rect.h>
-#include <GLES/egl.h>
+#include <EGL/egl.h>
#include <pixelflinger/format.h>
@@ -48,8 +48,6 @@
egl_native_window_t::incRef = &EGLNativeWindowSurface::hook_incRef;
egl_native_window_t::decRef = &EGLNativeWindowSurface::hook_decRef;
egl_native_window_t::swapBuffers = &EGLNativeWindowSurface::hook_swapBuffers;
- egl_native_window_t::nextBuffer = &EGLNativeWindowSurface::hook_nextBuffer;
- egl_native_window_t::setSwapRectangle = &EGLNativeWindowSurface::hook_setSwapRectangle;
egl_native_window_t::connect = &EGLNativeWindowSurface::hook_connect;
egl_native_window_t::disconnect = &EGLNativeWindowSurface::hook_disconnect;
@@ -98,18 +96,6 @@
return that->swapBuffers();
}
-uint32_t EGLNativeWindowSurface::hook_nextBuffer(NativeWindowType window)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- return that->nextBuffer();
-}
-
-void EGLNativeWindowSurface::hook_setSwapRectangle(NativeWindowType window, int l, int t, int w, int h)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- that->setSwapRectangle(l, t, w, h);
-}
-
void EGLNativeWindowSurface::setSwapRectangle(int l, int t, int w, int h)
{
mSurface->setSwapRectangle(Rect(l, t, l+w, t+h));
@@ -138,17 +124,6 @@
return 0;
}
-uint32_t EGLNativeWindowSurface::nextBuffer()
-{
- const sp<Surface>& surface(mSurface);
- Surface::SurfaceInfo info;
- surface->nextBuffer(&info);
- // update the address of the buffer to draw to next
- egl_native_window_t::base = intptr_t(info.base);
- egl_native_window_t::offset = intptr_t(info.bits) - intptr_t(info.base);
- return 0;
-}
-
void EGLNativeWindowSurface::connect()
{
if (!mConnected) {
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 700aa3a..3b29b09 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -71,10 +71,11 @@
EventHub::device_t::device_t(int32_t _id, const char* _path)
: id(_id), path(_path), classes(0)
- , layoutMap(new KeyLayoutMap()), next(NULL) {
+ , keyBitmask(NULL), layoutMap(new KeyLayoutMap()), next(NULL) {
}
EventHub::device_t::~device_t() {
+ delete [] keyBitmask;
delete layoutMap;
}
@@ -403,6 +404,36 @@
return true;
}
+/*
+ * Inspect the known devices to determine whether physical keys exist for the given
+ * framework-domain key codes.
+ */
+bool EventHub::hasKeys(size_t numCodes, int32_t* keyCodes, uint8_t* outFlags) {
+ for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) {
+ outFlags[codeIndex] = 0;
+
+ // check each available hardware device for support for this keycode
+ Vector<int32_t> scanCodes;
+ for (int n = 0; (n < mFDCount) && (outFlags[codeIndex] == 0); n++) {
+ if (mDevices[n]) {
+ status_t err = mDevices[n]->layoutMap->findScancodes(keyCodes[codeIndex], &scanCodes);
+ if (!err) {
+ // check the possible scan codes identified by the layout map against the
+ // map of codes actually emitted by the driver
+ for (size_t sc = 0; sc < scanCodes.size(); sc++) {
+ if (test_bit(scanCodes[sc], mDevices[n]->keyBitmask)) {
+ outFlags[codeIndex] = 1;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
// ----------------------------------------------------------------------------
int EventHub::open_device(const char *deviceName)
@@ -527,6 +558,16 @@
break;
}
}
+ if ((device->classes & CLASS_KEYBOARD) != 0) {
+ device->keyBitmask = new uint8_t[(KEY_MAX+1)/8];
+ if (device->keyBitmask != NULL) {
+ memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
+ } else {
+ delete device;
+ LOGE("out of memory allocating key bitmask");
+ return -1;
+ }
+ }
}
if (test_bit(BTN_MOUSE, key_bitmask)) {
uint8_t rel_bitmask[(REL_MAX+1)/8];
diff --git a/libs/ui/ICamera.cpp b/libs/ui/ICamera.cpp
index 7b0922e..ab0fef1 100644
--- a/libs/ui/ICamera.cpp
+++ b/libs/ui/ICamera.cpp
@@ -28,7 +28,7 @@
enum {
DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
SET_PREVIEW_DISPLAY,
- SET_FRAME_CALLBACK_FLAG,
+ SET_PREVIEW_CALLBACK_FLAG,
START_PREVIEW,
STOP_PREVIEW,
AUTO_FOCUS,
@@ -38,7 +38,11 @@
CONNECT,
LOCK,
UNLOCK,
- PREVIEW_ENABLED
+ PREVIEW_ENABLED,
+ START_RECORDING,
+ STOP_RECORDING,
+ RECORDING_ENABLED,
+ RELEASE_RECORDING_FRAME,
};
class BpCamera: public BpInterface<ICamera>
@@ -69,15 +73,15 @@
return reply.readInt32();
}
- // set the frame callback flag to affect how the received frames from
- // preview are handled.
- void setFrameCallbackFlag(int frame_callback_flag)
+ // 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("setFrameCallbackFlag(%d)", frame_callback_flag);
+ LOGV("setPreviewCallbackFlag(%d)", flag);
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
- data.writeInt32(frame_callback_flag);
- remote()->transact(SET_FRAME_CALLBACK_FLAG, data, &reply);
+ data.writeInt32(flag);
+ remote()->transact(SET_PREVIEW_CALLBACK_FLAG, data, &reply);
}
// start preview mode, must call setPreviewDisplay first
@@ -90,6 +94,16 @@
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()
{
@@ -99,6 +113,24 @@
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()
{
@@ -109,6 +141,16 @@
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()
{
@@ -202,11 +244,11 @@
reply->writeInt32(setPreviewDisplay(surface));
return NO_ERROR;
} break;
- case SET_FRAME_CALLBACK_FLAG: {
- LOGV("SET_FRAME_CALLBACK_TYPE");
+ case SET_PREVIEW_CALLBACK_FLAG: {
+ LOGV("SET_PREVIEW_CALLBACK_TYPE");
CHECK_INTERFACE(ICamera, data, reply);
- int frame_callback_flag = data.readInt32();
- setFrameCallbackFlag(frame_callback_flag);
+ int callback_flag = data.readInt32();
+ setPreviewCallbackFlag(callback_flag);
return NO_ERROR;
} break;
case START_PREVIEW: {
@@ -215,18 +257,43 @@
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);
diff --git a/libs/ui/ICameraClient.cpp b/libs/ui/ICameraClient.cpp
index c5d6d52..4bec9d2 100644
--- a/libs/ui/ICameraClient.cpp
+++ b/libs/ui/ICameraClient.cpp
@@ -28,9 +28,10 @@
SHUTTER_CALLBACK = IBinder::FIRST_CALL_TRANSACTION,
RAW_CALLBACK,
JPEG_CALLBACK,
- FRAME_CALLBACK,
+ PREVIEW_CALLBACK,
ERROR_CALLBACK,
- AUTOFOCUS_CALLBACK
+ AUTOFOCUS_CALLBACK,
+ RECORDING_CALLBACK,
};
class BpCameraClient: public BpInterface<ICameraClient>
@@ -70,14 +71,24 @@
remote()->transact(JPEG_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
}
- // callback from camera service to app with video frame data
- void frameCallback(const sp<IMemory>& frame)
+ // callback from camera service to app with preview frame data
+ void previewCallback(const sp<IMemory>& frame)
{
- LOGV("frameCallback");
+ LOGV("previewCallback");
Parcel data, reply;
data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
data.writeStrongBinder(frame->asBinder());
- remote()->transact(FRAME_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
+ remote()->transact(PREVIEW_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+
+ // callback from camera service to app with recording frame data
+ void recordingCallback(const sp<IMemory>& frame)
+ {
+ LOGV("recordingCallback");
+ Parcel data, reply;
+ data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
+ data.writeStrongBinder(frame->asBinder());
+ remote()->transact(RECORDING_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
}
// callback from camera service to app to report error
@@ -135,11 +146,18 @@
jpegCallback(picture);
return NO_ERROR;
} break;
- case FRAME_CALLBACK: {
- LOGV("FRAME_CALLBACK");
+ case PREVIEW_CALLBACK: {
+ LOGV("PREVIEW_CALLBACK");
CHECK_INTERFACE(ICameraClient, data, reply);
sp<IMemory> frame = interface_cast<IMemory>(data.readStrongBinder());
- frameCallback(frame);
+ previewCallback(frame);
+ return NO_ERROR;
+ } break;
+ case RECORDING_CALLBACK: {
+ LOGV("RECORDING_CALLBACK");
+ CHECK_INTERFACE(ICameraClient, data, reply);
+ sp<IMemory> frame = interface_cast<IMemory>(data.readStrongBinder());
+ recordingCallback(frame);
return NO_ERROR;
} break;
case ERROR_CALLBACK: {
diff --git a/libs/ui/ISurface.cpp b/libs/ui/ISurface.cpp
index 6f3cd47..d5e9f81 100644
--- a/libs/ui/ISurface.cpp
+++ b/libs/ui/ISurface.cpp
@@ -27,12 +27,33 @@
namespace android {
-enum {
- REGISTER_BUFFERS = IBinder::FIRST_CALL_TRANSACTION,
- UNREGISTER_BUFFERS,
- POST_BUFFER, // one-way transaction
- CREATE_OVERLAY,
-};
+ISurface::BufferHeap::BufferHeap()
+ : w(0), h(0), hor_stride(0), ver_stride(0), format(0),
+ transform(0), flags(0)
+{
+}
+
+ISurface::BufferHeap::BufferHeap(uint32_t w, uint32_t h,
+ int32_t hor_stride, int32_t ver_stride,
+ PixelFormat format, const sp<IMemoryHeap>& heap)
+ : w(w), h(h), hor_stride(hor_stride), ver_stride(ver_stride),
+ format(format), transform(0), flags(0), heap(heap)
+{
+}
+
+ISurface::BufferHeap::BufferHeap(uint32_t w, uint32_t h,
+ int32_t hor_stride, int32_t ver_stride,
+ PixelFormat format, uint32_t transform, uint32_t flags,
+ const sp<IMemoryHeap>& heap)
+ : w(w), h(h), hor_stride(hor_stride), ver_stride(ver_stride),
+ format(format), transform(transform), flags(flags), heap(heap)
+{
+}
+
+
+ISurface::BufferHeap::~BufferHeap()
+{
+}
class BpSurface : public BpInterface<ISurface>
{
@@ -42,17 +63,18 @@
{
}
- virtual status_t registerBuffers(int w, int h, int hstride, int vstride,
- PixelFormat format, const sp<IMemoryHeap>& heap)
+ virtual status_t registerBuffers(const BufferHeap& buffers)
{
Parcel data, reply;
data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
- data.writeInt32(w);
- data.writeInt32(h);
- data.writeInt32(hstride);
- data.writeInt32(vstride);
- data.writeInt32(format);
- data.writeStrongBinder(heap->asBinder());
+ data.writeInt32(buffers.w);
+ data.writeInt32(buffers.h);
+ data.writeInt32(buffers.hor_stride);
+ data.writeInt32(buffers.ver_stride);
+ data.writeInt32(buffers.format);
+ data.writeInt32(buffers.transform);
+ data.writeInt32(buffers.flags);
+ data.writeStrongBinder(buffers.heap->asBinder());
remote()->transact(REGISTER_BUFFERS, data, &reply);
status_t result = reply.readInt32();
return result;
@@ -102,13 +124,16 @@
switch(code) {
case REGISTER_BUFFERS: {
CHECK_INTERFACE(ISurface, data, reply);
- int w = data.readInt32();
- int h = data.readInt32();
- int hs= data.readInt32();
- int vs= data.readInt32();
- PixelFormat f = data.readInt32();
- sp<IMemoryHeap> heap(interface_cast<IMemoryHeap>(data.readStrongBinder()));
- status_t err = registerBuffers(w,h,hs,vs,f,heap);
+ BufferHeap buffer;
+ buffer.w = data.readInt32();
+ buffer.h = data.readInt32();
+ buffer.hor_stride = data.readInt32();
+ buffer.ver_stride= data.readInt32();
+ buffer.format = data.readInt32();
+ buffer.transform = data.readInt32();
+ buffer.flags = data.readInt32();
+ buffer.heap = interface_cast<IMemoryHeap>(data.readStrongBinder());
+ status_t err = registerBuffers(buffer);
reply->writeInt32(err);
return NO_ERROR;
} break;
diff --git a/libs/ui/PixelFormat.cpp b/libs/ui/PixelFormat.cpp
index 605c8ae..b65ed97 100644
--- a/libs/ui/PixelFormat.cpp
+++ b/libs/ui/PixelFormat.cpp
@@ -19,6 +19,18 @@
namespace android {
+size_t PixelFormatInfo::getScanlineSize(unsigned int width) const
+{
+ size_t size;
+ if ((components >= 6) && (components <= 8)) {
+ // YCbCr formats are differents.
+ size = (width * bitsPerPixel)>>3;
+ } else {
+ size = width * bytesPerPixel;
+ }
+ return size;
+}
+
ssize_t bytesPerPixel(PixelFormat format)
{
PixelFormatInfo info;
@@ -47,7 +59,25 @@
if (!valid) {
return BAD_INDEX;
}
-
+
+ #define COMPONENT(name) \
+ case GGL_##name: info->components = PixelFormatInfo::name; break;
+
+ switch (i->components) {
+ COMPONENT(ALPHA)
+ COMPONENT(RGB)
+ 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;
+ }
+
+ #undef COMPONENT
+
info->format = format;
info->bytesPerPixel = i->size;
info->bitsPerPixel = i->bitsPerPixel;
@@ -59,6 +89,7 @@
info->l_green = i->gl;
info->h_blue = i->bh;
info->l_blue = i->bl;
+
return NO_ERROR;
}
diff --git a/libs/utils/CallStack.cpp b/libs/utils/CallStack.cpp
index 26fb22a..2fdaa71 100644
--- a/libs/utils/CallStack.cpp
+++ b/libs/utils/CallStack.cpp
@@ -120,13 +120,18 @@
char name[];
};
- const char *map_to_name(uint64_t pc, const char* def) {
+ const char *map_to_name(uint64_t pc, const char* def, uint64_t* start) {
mapinfo* mi = getMapInfoList();
while(mi) {
- if ((pc >= mi->start) && (pc < mi->end))
+ if ((pc >= mi->start) && (pc < mi->end)) {
+ if (start)
+ *start = mi->start;
return mi->name;
+ }
mi = mi->next;
}
+ if (start)
+ *start = 0;
return def;
}
@@ -183,8 +188,15 @@
}
}
- static const char *mapAddressToName(const void* pc, const char* def) {
- return sMapInfo.map_to_name((uint64_t)pc, def);
+ static const char *mapAddressToName(const void* pc, const char* def,
+ void const** start)
+ {
+ uint64_t s;
+ char const* name = sMapInfo.map_to_name(uint64_t(uintptr_t(pc)), def, &s);
+ if (start) {
+ *start = (void*)s;
+ }
+ return name;
}
};
@@ -297,8 +309,9 @@
res.append(name);
res.append(tmp2);
} else {
- name = MapInfo::mapAddressToName(ip, "<unknown>");
- snprintf(tmp, 256, "pc %p %s", ip, name);
+ void const* start = 0;
+ name = MapInfo::mapAddressToName(ip, "<unknown>", &start);
+ snprintf(tmp, 256, "pc %08lx %s", uintptr_t(ip)-uintptr_t(start), name);
res.append(tmp);
}
res.append("\n");
diff --git a/libs/utils/Parcel.cpp b/libs/utils/Parcel.cpp
index 2962b25..4225e67 100644
--- a/libs/utils/Parcel.cpp
+++ b/libs/utils/Parcel.cpp
@@ -658,15 +658,20 @@
status_t err;
err = writeInt32(handle.numFds);
if (err != NO_ERROR) return err;
-
+
err = writeInt32(handle.numInts);
if (err != NO_ERROR) return err;
-
+
for (int i=0 ; err==NO_ERROR && i<handle.numFds ; i++)
err = writeDupFileDescriptor(handle.data[i]);
-
+
+ if (err != NO_ERROR) {
+ LOGD("write native handle, write dup fd failed");
+ return err;
+ }
+
err = write(handle.data + handle.numFds, sizeof(int)*handle.numInts);
-
+
return err;
}
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 5a09fb4..2ad3bfe 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -176,7 +176,9 @@
void* Res_png_9patch::serialize()
{
- void* newData = malloc(serializedSize());
+ // Use calloc since we're going to leave a few holes in the data
+ // and want this to run cleanly under valgrind
+ void* newData = calloc(1, serializedSize());
serialize(newData);
return newData;
}
@@ -1736,7 +1738,7 @@
}
ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag,
- uint32_t* outSpecFlags) const
+ uint32_t* outSpecFlags, ResTable_config* outConfig) const
{
if (mError != NO_ERROR) {
return mError;
@@ -1809,7 +1811,7 @@
(const Res_value*)(((const uint8_t*)type) + offset);
ResTable_config thisConfig;
thisConfig.copyFromDtoH(type->config);
-
+
if (outSpecFlags != NULL) {
if (typeClass->typeSpecFlags != NULL) {
*outSpecFlags |= dtohl(typeClass->typeSpecFlags[e]);
@@ -1834,6 +1836,9 @@
outValue->res0 = bestValue->res0;
outValue->dataType = bestValue->dataType;
outValue->data = dtohl(bestValue->data);
+ if (outConfig != NULL) {
+ *outConfig = bestItem;
+ }
TABLE_NOISY(size_t len;
printf("Found value: pkg=%d, type=%d, str=%s, int=%d\n",
bestPackage->header->index,
@@ -3147,13 +3152,13 @@
const char16_t* pos = s;
while (pos < end && !failed) {
const char16_t* start = pos;
- end++;
+ pos++;
while (pos < end && *pos != '|') {
pos++;
}
- //printf("Looking for: %s\n", String8(start, pos-start).string());
+ //printf("Looking for: %s\n", String8(start, pos-start).string());
const bag_entry* bagi = bag;
- ssize_t i;
+ ssize_t i;
for (i=0; i<cnt; i++, bagi++) {
if (!Res_INTERNALID(bagi->map.name.ident)) {
//printf("Trying attr #%08x\n", bagi->map.name.ident);
@@ -3181,7 +3186,7 @@
}
unlockBag(bag);
if (!failed) {
- //printf("Final flag value: 0x%lx\n", outValue->data);
+ //printf("Final flag value: 0x%lx\n", outValue->data);
return true;
}
}
@@ -3189,7 +3194,7 @@
if (fromAccessor) {
if (accessor->getAttributeFlags(attrID, s, len, outValue)) {
- //printf("Final flag value: 0x%lx\n", outValue->data);
+ //printf("Final flag value: 0x%lx\n", outValue->data);
return true;
}
}
@@ -3484,7 +3489,7 @@
ResTable_config thisConfig;
thisConfig.copyFromDtoH(thisType->config);
-
+
TABLE_GETENTRY(LOGI("Match entry 0x%x in type 0x%x (sz 0x%x): imsi:%d/%d=%d/%d lang:%c%c=%c%c cnt:%c%c=%c%c "
"orien:%d=%d touch:%d=%d density:%d=%d key:%d=%d inp:%d=%d nav:%d=%d w:%d=%d h:%d=%d\n",
entryIndex, typeIndex+1, dtohl(thisType->config.size),
diff --git a/libs/utils/String16.cpp b/libs/utils/String16.cpp
index 1f81cad..aef67f2 100644
--- a/libs/utils/String16.cpp
+++ b/libs/utils/String16.cpp
@@ -244,7 +244,6 @@
// ---------------------------------------------------------------------------
-// Note: not dealing with generating surrogate pairs.
static char16_t* allocFromUTF8(const char* in, size_t len)
{
if (len == 0) return getEmptyString();
@@ -255,7 +254,10 @@
while (p < end) {
chars++;
- p += utf8_char_len(*p);
+ int utf8len = utf8_char_len(*p);
+ uint32_t codepoint = utf8_to_utf32((const uint8_t*)p, utf8len);
+ if (codepoint > 0xFFFF) chars++; // this will be a surrogate pair in utf16
+ p += utf8len;
}
SharedBuffer* buf = SharedBuffer::alloc((chars+1)*sizeof(char16_t));
@@ -265,7 +267,19 @@
char16_t* d = str;
while (p < end) {
size_t len = utf8_char_len(*p);
- *d++ = (char16_t)utf8_to_utf32((const uint8_t*)p, len);
+ 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;
@@ -388,7 +402,7 @@
->editResize((len+1)*sizeof(char16_t));
if (buf) {
char16_t* str = (char16_t*)buf->data();
- memcpy(str, other, len*sizeof(char16_t));
+ memmove(str, other, len*sizeof(char16_t));
str[len] = 0;
mString = str;
return NO_ERROR;
diff --git a/libs/utils/String8.cpp b/libs/utils/String8.cpp
index ab843f6..c50d343 100644
--- a/libs/utils/String8.cpp
+++ b/libs/utils/String8.cpp
@@ -317,8 +317,10 @@
->editResize(myLen+otherLen+1);
if (buf) {
char* str = (char*)buf->data();
- memcpy(str+myLen, other, otherLen+1);
mString = str;
+ str += myLen;
+ memcpy(str, other, otherLen);
+ str[otherLen] = '\0';
return NO_ERROR;
}
return NO_MEMORY;
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index 74271ba..9287c0b 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+// #define LOG_NDEBUG 0
#define LOG_TAG "libutils.threads"
#include <utils/threads.h>
@@ -838,146 +839,6 @@
#error "condition variables not supported on this platform"
#endif
-
-/*
- * ===========================================================================
- * ReadWriteLock class
- * ===========================================================================
- */
-
-#if 0
-#pragma mark -
-#pragma mark ReadWriteLock
-#endif
-
-/*
- * Add a reader. Readers are nice. They share.
- */
-void ReadWriteLock::lockForRead()
-{
- mLock.lock();
- while (mNumWriters > 0) {
- LOG(LOG_DEBUG, "thread", "+++ lockForRead: waiting\n");
- mReadWaiter.wait(mLock);
- }
- assert(mNumWriters == 0);
- mNumReaders++;
-#if defined(PRINT_RENDER_TIMES)
- if (mNumReaders == 1)
- mDebugTimer.start();
-#endif
- mLock.unlock();
-}
-
-/*
- * Try to add a reader. If it doesn't work right away, return "false".
- */
-bool ReadWriteLock::tryLockForRead()
-{
- mLock.lock();
- if (mNumWriters > 0) {
- mLock.unlock();
- return false;
- }
- assert(mNumWriters == 0);
- mNumReaders++;
-#if defined(PRINT_RENDER_TIMES)
- if (mNumReaders == 1)
- mDebugTimer.start();
-#endif
- mLock.unlock();
- return true;
-}
-
-/*
- * Remove a reader.
- */
-void ReadWriteLock::unlockForRead()
-{
- mLock.lock();
- if (mNumReaders == 0) {
- LOG(LOG_WARN, "thread",
- "WARNING: unlockForRead requested, but not locked\n");
- return;
- }
- assert(mNumReaders > 0);
- assert(mNumWriters == 0);
- mNumReaders--;
- if (mNumReaders == 0) { // last reader?
-#if defined(PRINT_RENDER_TIMES)
- mDebugTimer.stop();
- printf(" rdlk held %.3f msec\n",
- (double) mDebugTimer.durationUsecs() / 1000.0);
-#endif
- //printf("+++ signaling writers (if any)\n");
- mWriteWaiter.signal(); // wake one writer (if any)
- }
- mLock.unlock();
-}
-
-/*
- * Add a writer. This requires exclusive access to the object.
- */
-void ReadWriteLock::lockForWrite()
-{
- mLock.lock();
- while (mNumReaders > 0 || mNumWriters > 0) {
- LOG(LOG_DEBUG, "thread", "+++ lockForWrite: waiting\n");
- mWriteWaiter.wait(mLock);
- }
- assert(mNumReaders == 0);
- assert(mNumWriters == 0);
- mNumWriters++;
-#if defined(PRINT_RENDER_TIMES)
- mDebugTimer.start();
-#endif
- mLock.unlock();
-}
-
-/*
- * Try to add a writer. If it doesn't work right away, return "false".
- */
-bool ReadWriteLock::tryLockForWrite()
-{
- mLock.lock();
- if (mNumReaders > 0 || mNumWriters > 0) {
- mLock.unlock();
- return false;
- }
- assert(mNumReaders == 0);
- assert(mNumWriters == 0);
- mNumWriters++;
-#if defined(PRINT_RENDER_TIMES)
- mDebugTimer.start();
-#endif
- mLock.unlock();
- return true;
-}
-
-/*
- * Remove a writer.
- */
-void ReadWriteLock::unlockForWrite()
-{
- mLock.lock();
- if (mNumWriters == 0) {
- LOG(LOG_WARN, "thread",
- "WARNING: unlockForWrite requested, but not locked\n");
- return;
- }
- assert(mNumWriters == 1);
- mNumWriters--;
-#if defined(PRINT_RENDER_TIMES)
- mDebugTimer.stop();
- //printf(" wrlk held %.3f msec\n",
- // (double) mDebugTimer.durationUsecs() / 1000.0);
-#endif
- // mWriteWaiter.signal(); // should other writers get first dibs?
- //printf("+++ signaling readers (if any)\n");
- mReadWaiter.broadcast(); // wake all readers (if any)
- mLock.unlock();
-}
-
// ----------------------------------------------------------------------------
#if 0
@@ -1025,6 +886,8 @@
// hold a strong reference on ourself
mHoldSelf = this;
+ mRunning = true;
+
bool res;
if (mCanCallJava) {
res = createThreadEtc(_threadLoop,
@@ -1038,14 +901,16 @@
mStatus = UNKNOWN_ERROR; // something happened!
mRunning = false;
mThread = thread_id_t(-1);
+ mHoldSelf.clear(); // "this" may have gone away after this.
+
+ return UNKNOWN_ERROR;
}
- if (mStatus < 0) {
- // something happened, don't leak
- mHoldSelf.clear();
- }
-
- return mStatus;
+ // Do not refer to mStatus here: The thread is already running (may, in fact
+ // already have exited with a valid mStatus result). The NO_ERROR indication
+ // here merely indicates successfully starting the thread and does not
+ // imply successful termination/execution.
+ return NO_ERROR;
}
int Thread::_threadLoop(void* user)
@@ -1055,20 +920,32 @@
wp<Thread> weak(strong);
self->mHoldSelf.clear();
- // we're about to run...
- self->mStatus = self->readyToRun();
- if (self->mStatus!=NO_ERROR || self->mExitPending) {
- // pretend the thread never started...
- self->mExitPending = false;
- self->mRunning = false;
- return 0;
- }
-
- // thread is running now
- self->mRunning = true;
+ bool first = true;
do {
- bool result = self->threadLoop();
+ bool result;
+ if (first) {
+ first = false;
+ self->mStatus = self->readyToRun();
+ result = (self->mStatus == NO_ERROR);
+
+ if (result && !self->mExitPending) {
+ // Binder threads (and maybe others) rely on threadLoop
+ // running at least once after a successful ::readyToRun()
+ // (unless, of course, the thread has already been asked to exit
+ // at that point).
+ // This is because threads are essentially used like this:
+ // (new ThreadSubclass())->run();
+ // The caller therefore does not retain a strong reference to
+ // the thread and the thread would simply disappear after the
+ // successful ::readyToRun() call instead of entering the
+ // threadLoop at least once.
+ result = self->threadLoop();
+ }
+ } else {
+ result = self->threadLoop();
+ }
+
if (result == false || self->mExitPending) {
self->mExitPending = true;
self->mLock.lock();
@@ -1095,24 +972,23 @@
status_t Thread::requestExitAndWait()
{
- if (mStatus == OK) {
+ if (mThread == getThreadId()) {
+ LOGW(
+ "Thread (this=%p): don't call waitForExit() from this "
+ "Thread object's thread. It's a guaranteed deadlock!",
+ this);
- if (mThread == getThreadId()) {
- LOGW(
- "Thread (this=%p): don't call waitForExit() from this "
- "Thread object's thread. It's a guaranteed deadlock!",
- this);
- return WOULD_BLOCK;
- }
-
- requestExit();
-
- Mutex::Autolock _l(mLock);
- while (mRunning == true) {
- mThreadExitedCondition.wait(mLock);
- }
- mExitPending = false;
+ return WOULD_BLOCK;
}
+
+ requestExit();
+
+ Mutex::Autolock _l(mLock);
+ while (mRunning == true) {
+ mThreadExitedCondition.wait(mLock);
+ }
+ mExitPending = false;
+
return mStatus;
}