diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-02-13 12:57:50 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-02-13 12:57:50 -0800 |
commit | da996f390e17e16f2dfa60e972e7ebc4f868f37e (patch) | |
tree | 00a0f15270d4c7b619fd34d8383257e1761082f4 /libs | |
parent | d24b8183b93e781080b2c16c487e60d51c12da31 (diff) | |
download | frameworks_base-da996f390e17e16f2dfa60e972e7ebc4f868f37e.zip frameworks_base-da996f390e17e16f2dfa60e972e7ebc4f868f37e.tar.gz frameworks_base-da996f390e17e16f2dfa60e972e7ebc4f868f37e.tar.bz2 |
auto import from //branches/cupcake/...@131421
Diffstat (limited to 'libs')
-rw-r--r-- | libs/audioflinger/AudioFlinger.cpp | 1949 | ||||
-rw-r--r-- | libs/audioflinger/AudioFlinger.h | 612 | ||||
-rw-r--r-- | libs/surfaceflinger/Android.mk | 2 | ||||
-rw-r--r-- | libs/surfaceflinger/Layer.cpp | 4 | ||||
-rw-r--r-- | libs/surfaceflinger/LayerBase.cpp | 17 | ||||
-rw-r--r-- | libs/surfaceflinger/LayerBase.h | 23 | ||||
-rw-r--r-- | libs/surfaceflinger/LayerBuffer.cpp | 53 | ||||
-rw-r--r-- | libs/surfaceflinger/LayerBuffer.h | 6 | ||||
-rw-r--r-- | libs/surfaceflinger/LayerOrientationAnim.cpp | 2 | ||||
-rw-r--r-- | libs/surfaceflinger/LayerScreenshot.cpp | 110 | ||||
-rw-r--r-- | libs/surfaceflinger/LayerScreenshot.h | 57 | ||||
-rw-r--r-- | libs/surfaceflinger/RFBServer.cpp | 722 | ||||
-rw-r--r-- | libs/surfaceflinger/RFBServer.h | 316 | ||||
-rw-r--r-- | libs/surfaceflinger/SurfaceFlinger.cpp | 141 | ||||
-rw-r--r-- | libs/surfaceflinger/SurfaceFlinger.h | 4 | ||||
-rw-r--r-- | libs/ui/ISurface.cpp | 2 |
16 files changed, 1743 insertions, 2277 deletions
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp index 017a298..d347f14 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,13 @@ static const float MAX_GAIN = 4096.0f; static const int8_t kMaxTrackRetries = 50; static const int8_t kMaxTrackStartupRetries = 50; +static const int kStartSleepTime = 30000; +static const int kStopSleepTime = 30000; + +// Maximum number of pending buffers allocated by OutputTrack::write() +static const uint8_t kMaxOutputTrackBuffers = 5; + + #define AUDIOFLINGER_SECURITY_ENABLED 1 // ---------------------------------------------------------------------------- @@ -98,13 +114,10 @@ static bool settingsAllowed() { // ---------------------------------------------------------------------------- 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), mA2dpEnabledReq(false), + mForcedSpeakerCount(0), mForcedRoute(0), mRouteRestoreTime(0), mMusicMuteSaved(false) { mHardwareStatus = AUDIO_HW_IDLE; mAudioHardware = AudioHardwareInterface::create(); @@ -113,42 +126,43 @@ AudioFlinger::AudioFlinger() // 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); if (mAudioRecordThread != 0) { @@ -162,7 +176,7 @@ AudioFlinger::AudioFlinger() property_get("ro.audio.silent", value, "0"); if (atoi(value)) { LOGD("Silence is golden"); - mMasterMute = true; + setMasterMute(true); } } @@ -172,63 +186,35 @@ AudioFlinger::~AudioFlinger() 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; - mWaitWorkCV.broadcast(); -} - -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; - notifyOutputChange_l(); +#endif } -size_t AudioFlinger::getOutputFrameCount(AudioStreamOut* output) -{ - return output->bufferSize() / output->channelCount() / sizeof(int16_t); -} #ifdef WITH_A2DP -bool AudioFlinger::streamDisablesA2dp(int streamType) +void AudioFlinger::setA2dpEnabled(bool enable) { - return (streamType == AudioTrack::SYSTEM || - streamType == AudioTrack::RING || - streamType == AudioTrack::ALARM || - streamType == AudioTrack::VOICE_CALL || - streamType == AudioTrack::BLUETOOTH_SCO || - streamType == AudioTrack::NOTIFICATION); + LOGV_IF(enable, "set output to A2DP\n"); + LOGV_IF(!enable, "set output to hardware audio\n"); + + mA2dpEnabledReq = enable; + mA2dpMixerThread->wakeUp(); } +#endif // WITH_A2DP -void AudioFlinger::setA2dpEnabled(bool enable) +bool AudioFlinger::streamForcedToSpeaker(int streamType) { - if (enable) { - LOGD("set output to A2DP\n"); - setOutput(mA2dpOutput); - } else { - LOGD("set output to hardware audio\n"); - setOutput(mHardwareOutput); - } + // 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); } -#endif // WITH_A2DP status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args) { @@ -251,40 +237,6 @@ status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args) 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) { @@ -292,18 +244,6 @@ status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args) char buffer[SIZE]; String8 result; - snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", audioMixer()->trackNames()); - result.append(buffer); - snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime)); - result.append(buffer); - snprintf(buffer, SIZE, "total writes: %d\n", mNumWrites); - result.append(buffer); - snprintf(buffer, SIZE, "delayed writes: %d\n", mNumDelayedWrites); - result.append(buffer); - snprintf(buffer, SIZE, "blocked in write: %d\n", mInWrite); - result.append(buffer); - snprintf(buffer, SIZE, "standby: %d\n", mStandby); - result.append(buffer); snprintf(buffer, SIZE, "Hardware status: %d\n", mHardwareStatus); result.append(buffer); write(fd, result.string(), result.size()); @@ -332,8 +272,12 @@ status_t AudioFlinger::dump(int fd, const Vector<String16>& args) AutoMutex lock(&mLock); dumpClients(fd, args); - dumpTracks(fd, args); dumpInternals(fd, args); + mHardwareMixerThread->dump(fd, args); +#ifdef WITH_A2DP + mA2dpMixerThread->dump(fd, args); +#endif + if (mAudioHardware) { mAudioHardware->dumpState(fd, args); } @@ -341,226 +285,9 @@ status_t AudioFlinger::dump(int fd, const Vector<String16>& args) 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(); - nsecs_t outputSwitchStandbyTime = 0; - - 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; - } - if (outputSwitchStandbyTime) { - AudioStreamOut *output = (mOutput == mHardwareOutput) ? mA2dpOutput : mHardwareOutput; - output->standby(); - outputSwitchStandbyTime = 0; - } - 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) { - outputSwitchStandbyTime = systemTime() + milliseconds(mOutput->latency()); - } - - // change output - doSetOutput(mRequestedOutput); - } - if (outputSwitchStandbyTime && systemTime() > outputSwitchStandbyTime) { - AudioStreamOut *output = (mOutput == mHardwareOutput) ? mA2dpOutput : mHardwareOutput; - output->standby(); - outputSwitchStandbyTime = 0; - } - - // 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); - 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; -} +// IAudioFlinger interface -void AudioFlinger::onFirstRef() -{ - run("AudioFlinger", ANDROID_PRIORITY_URGENT_AUDIO); -} -// IAudioFlinger interface sp<IAudioTrack> AudioFlinger::createTrack( pid_t pid, int streamType, @@ -572,34 +299,21 @@ sp<IAudioTrack> AudioFlinger::createTrack( 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) { @@ -608,13 +322,20 @@ sp<IAudioTrack> AudioFlinger::createTrack( client = new Client(this, pid); mClients.add(pid, client); } - - track = new Track(this, client, streamType, sampleRate, format, - channelCount, frameCount, sharedBuffer); - mTracks.add(track); - trackHandle = new TrackHandle(track); - - lStatus = NO_ERROR; +#ifdef WITH_A2DP + if (isA2dpEnabled() && AudioSystem::routedToA2dpOutput(streamType)) { + track = mA2dpMixerThread->createTrack(client, streamType, sampleRate, format, + channelCount, frameCount, sharedBuffer, &lStatus); + } else +#endif + { + track = mHardwareMixerThread->createTrack(client, streamType, sampleRate, format, + channelCount, frameCount, sharedBuffer, &lStatus); + } + if (track != NULL) { + trackHandle = new TrackHandle(track); + lStatus = NO_ERROR; + } } Exit: @@ -624,34 +345,54 @@ Exit: 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) @@ -665,12 +406,14 @@ status_t AudioFlinger::setMasterVolume(float value) 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; } @@ -688,20 +431,17 @@ status_t AudioFlinger::setRouting(int mode, uint32_t routes, uint32_t mask) } #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"); + LOGV("setOutput done\n"); } #endif @@ -714,6 +454,12 @@ status_t AudioFlinger::setRouting(int mode, uint32_t routes, uint32_t mask) 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); } @@ -726,9 +472,14 @@ uint32_t AudioFlinger::getRouting(int mode) const { uint32_t routes = 0; if ((mode >= AudioSystem::MODE_CURRENT) && (mode < AudioSystem::NUM_MODES)) { - mHardwareStatus = AUDIO_HW_GET_ROUTING; - mAudioHardware->getRouting(mode, &routes); - mHardwareStatus = AUDIO_HW_IDLE; + 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); } @@ -791,19 +542,21 @@ status_t AudioFlinger::setMasterMute(bool muted) 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) @@ -813,14 +566,25 @@ status_t AudioFlinger::setStreamVolume(int stream, float value) return PERMISSION_DENIED; } - if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) { + if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) { return BAD_VALUE; } - mStreamTypes[stream].volume = value; + mHardwareMixerThread->setStreamVolume(stream, value); +#ifdef WITH_A2DP + mA2dpMixerThread->setStreamVolume(stream, value); +#endif + status_t ret = NO_ERROR; - if (stream == AudioTrack::VOICE_CALL || - stream == AudioTrack::BLUETOOTH_SCO) { + if (stream == AudioSystem::VOICE_CALL || + stream == AudioSystem::BLUETOOTH_SCO) { + + if (stream == AudioSystem::VOICE_CALL) { + value = (float)AudioSystem::logToLinear(value)/100.0f; + } else { // (type == AudioSystem::BLUETOOTH_SCO) + value = 1.0f; + } + AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_SET_VOICE_VOLUME; ret = mAudioHardware->setVoiceVolume(value); @@ -837,59 +601,58 @@ status_t AudioFlinger::setStreamMute(int stream, bool muted) return PERMISSION_DENIED; } - if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) { + if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) { return BAD_VALUE; } + #ifdef WITH_A2DP - if (stream == AudioTrack::MUSIC) + mA2dpMixerThread->setStreamMute(stream, muted); +#endif + if (stream == AudioSystem::MUSIC) { - AutoMutex lock(&mLock); - if (mA2dpDisableCount > 0) + AutoMutex lock(&mHardwareLock); + if (mForcedRoute != 0) mMusicMuteSaved = muted; else - mStreamTypes[stream].mute = muted; + mHardwareMixerThread->setStreamMute(stream, muted); } else { - mStreamTypes[stream].mute = muted; + mHardwareMixerThread->setStreamMute(stream, muted); } -#else - mStreamTypes[stream].mute = muted; -#endif + + + 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; } - return mStreamTypes[stream].volume; + return mHardwareMixerThread->streamVolume(stream); } bool AudioFlinger::streamMute(int stream) const { - if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) { + if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) { return true; } -#ifdef WITH_A2DP - if (stream == AudioTrack::MUSIC && mA2dpDisableCount > 0) + + if (stream == AudioSystem::MUSIC && mForcedRoute != 0) { return mMusicMuteSaved; } -#endif - return mStreamTypes[stream].mute; + 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) @@ -897,6 +660,8 @@ status_t AudioFlinger::setParameter(const char* key, const char* value) 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); @@ -907,9 +672,15 @@ status_t AudioFlinger::setParameter(const char* key, const char* value) 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(); @@ -917,21 +688,13 @@ void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client) LOGV("Adding notification client %p", binder.get()); binder->linkToDeath(this); mNotificationClients.add(binder); + client->a2dpEnabledChanged(isA2dpEnabled()); } } - -size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int channelCount) -{ - return mAudioHardware->getInputBufferSize(sampleRate, format, channelCount); -} - -void AudioFlinger::wakeUp() -{ - mWaitWorkCV.broadcast(); -} - 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(); @@ -945,29 +708,680 @@ void AudioFlinger::binderDied(const wp<IBinder>& who) { } } -// must be called with mLock held -void AudioFlinger::notifyOutputChange_l() +void AudioFlinger::handleOutputSwitch() { - size_t size = mNotificationClients.size(); - uint32_t latency = mOutput->latency(); - 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->audioOutputChanged(mFrameCount, mSampleRate, latency); + if (mA2dpEnabled != mA2dpEnabledReq) + { + Mutex::Autolock _l(mLock); + + if (mA2dpEnabled != mA2dpEnabledReq) + { + mA2dpEnabled = mA2dpEnabledReq; + SortedVector < sp<MixerThread::Track> > tracks; + SortedVector < wp<MixerThread::Track> > activeTracks; + + // We hold mA2dpMixerThread mLock already + Mutex::Autolock _l(mHardwareMixerThread->mLock); + + // Transfer tracks playing on MUSIC stream from one mixer to the other + if (mA2dpEnabled) { + mHardwareMixerThread->getTracks(tracks, activeTracks); + mA2dpMixerThread->putTracks(tracks, activeTracks); + } else { + mA2dpMixerThread->getTracks(tracks, activeTracks); + mHardwareMixerThread->putTracks(tracks, activeTracks); + } + + // 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); + } + } + + mHardwareMixerThread->wakeUp(); } } } 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) +void AudioFlinger::wakeUp() +{ + mHardwareMixerThread->wakeUp(); +#ifdef WITH_A2DP + mA2dpMixerThread->wakeUp(); +#endif // WITH_A2DP +} + +bool AudioFlinger::isA2dpEnabled() const +{ + return mA2dpEnabledReq; +} + +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; + } +} + + +// ---------------------------------------------------------------------------- + +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 mLock + + Mutex::Autolock _l(mLock); + +#ifdef WITH_A2DP + if (mOutputType == AudioSystem::AUDIO_OUTPUT_A2DP) { + mAudioFlinger->handleOutputSwitch(); + } + if (mOutputTrack != NULL && !mAudioFlinger->isA2dpEnabled()) { + if (outputTrackActive) { + mOutputTrack->stop(); + outputTrackActive = false; + } + } +#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); +// mAudioFlinger->mHardwareStatus = AUDIO_HW_STANDBY; + if (!mStandby) { + mOutput->standby(); + mStandby = true; + } + +#ifdef WITH_A2DP + if (outputTrackActive) { + mOutputTrack->stop(); + outputTrackActive = false; + } +#endif + if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) { + mAudioFlinger->handleForcedSpeakerRoute(FORCE_ROUTE_RESTORE); + } +// 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, output %d\n", mOutputType); + 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(track); + if (track->isTerminated()) { + mTracks.remove(track); + deleteTrackName(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); +} + + +sp<AudioFlinger::MixerThread::Track> AudioFlinger::MixerThread::createTrack( + 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; + } + + { + Mutex::Autolock _l(mLock); + + if (mSampleRate == 0) { + LOGE("Audio driver not initialized."); + lStatus = NO_INIT; + goto Exit; + } + + track = new Track(this, client, streamType, sampleRate, format, + channelCount, frameCount, sharedBuffer); + mTracks.add(track); + lStatus = NO_ERROR; + } + +Exit: + if(status) { + *status = lStatus; + } + return track; +} + +void AudioFlinger::MixerThread::getTracks( + SortedVector < sp<Track> >& tracks, + SortedVector < wp<Track> >& activeTracks) +{ + size_t size = mTracks.size(); + LOGV ("MixerThread::getTracks() 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(activeTracks[i]); + } + + size = tracks.size(); + for (size_t i = 0; i < size; i++) { + sp<Track> t = tracks[i]; + mTracks.remove(t); + deleteTrackName(t->name()); + } +} + +void AudioFlinger::MixerThread::putTracks( + SortedVector < sp<Track> >& tracks, + SortedVector < wp<Track> >& activeTracks) +{ + + LOGV ("MixerThread::putTracks() 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(); + + if (name < 0) return; + + t->mName = name; + t->mMixerThread = this; + mTracks.add(t); + + int j = activeTracks.indexOf(t); + if (j >= 0) { + addActiveTrack(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; +} + +status_t AudioFlinger::MixerThread::addTrack(const sp<Track>& track) +{ + status_t status = ALREADY_EXISTS; Mutex::Autolock _l(mLock); // here the track could be either new, or restarted @@ -981,9 +1395,6 @@ status_t AudioFlinger::addTrack(const sp<Track>& track) } // 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 @@ -991,12 +1402,16 @@ status_t AudioFlinger::addTrack(const sp<Track>& track) track->mFillingUpStatus = Track::FS_FILLING; track->mResetDone = false; addActiveTrack(track); - return NO_ERROR; + status = NO_ERROR; } - return ALREADY_EXISTS; + + LOGV("mWaitWorkCV.broadcast"); + mWaitWorkCV.broadcast(); + + return status; } -void AudioFlinger::removeTrack(wp<Track> track, int name) +void AudioFlinger::MixerThread::removeTrack(wp<Track> track, int name) { Mutex::Autolock _l(mLock); sp<Track> t = track.promote(); @@ -1005,7 +1420,7 @@ void AudioFlinger::removeTrack(wp<Track> track, int name) } } -void AudioFlinger::remove_track_l(wp<Track> track, int name) +void AudioFlinger::MixerThread::remove_track_l(wp<Track> track, int name) { sp<Track> t = track.promote(); if (t!=NULL) { @@ -1016,7 +1431,7 @@ void AudioFlinger::remove_track_l(wp<Track> track, int name) mWaitWorkCV.broadcast(); } -void AudioFlinger::destroyTrack(const sp<Track>& track) +void AudioFlinger::MixerThread::destroyTrack(const sp<Track>& track) { // NOTE: We're acquiring a strong reference on the track before // acquiring the lock, this is to make sure removing it from @@ -1033,99 +1448,58 @@ void AudioFlinger::destroyTrack(const sp<Track>& track) } } -void AudioFlinger::addActiveTrack(const wp<Track>& t) + +void AudioFlinger::MixerThread::addActiveTrack(const wp<Track>& t) { mActiveTracks.add(t); -#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; - mMusicMuteSaved = mStreamTypes[AudioTrack::MUSIC].mute; - mStreamTypes[AudioTrack::MUSIC].mute = true; - LOGV("mA2dpSuppressed = true, track %d\n", track->name()); - } - LOGV("mA2dpDisableCount incremented to %d, track %d\n", mA2dpDisableCount, track->name()); + // 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); + } } -#endif } -void AudioFlinger::removeActiveTrack(const wp<Track>& t) +void AudioFlinger::MixerThread::removeActiveTrack(const wp<Track>& t) { mActiveTracks.remove(t); -#ifdef WITH_A2DP - // disable A2DP for certain stream types - sp<Track> track = t.promote(); - if (streamDisablesA2dp(track->type())) { - if (mA2dpDisableCount > 0) { - mA2dpDisableCount--; - LOGV("mA2dpDisableCount decremented to %d, track %d\n", mA2dpDisableCount, track->name()); - if (mA2dpDisableCount == 0 && mA2dpSuppressed) { - setA2dpEnabled(true); - mA2dpSuppressed = false; - mStreamTypes[AudioTrack::MUSIC].mute = mMusicMuteSaved; - LOGV("mA2dpSuppressed = false, track %d\n", track->name()); - } - } else - LOGE("mA2dpDisableCount is already zero"); - } -#endif -} -int AudioFlinger::getTrackName() -{ - // Both mixers must have the same set of track used to avoid mismatches when - // switching from A2DP output to hardware output - int a2DpName; - int hwName; -#ifdef WITH_A2DP - a2DpName = mA2dpAudioMixer->getTrackName(); -#endif - hwName = mHardwareAudioMixer->getTrackName(); - - LOGW_IF((a2DpName != hwName), "getTrackName track name mismatch! A2DP %d, HW %d", a2DpName, hwName); - - return hwName; -} + // 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; -void AudioFlinger::deleteTrackName(int name) -{ - // Both mixers must have the same set of track used to avoid mismatches when - // switching from A2DP output to hardware output - mHardwareAudioMixer->deleteTrackName(name); -#ifdef WITH_A2DP - mA2dpAudioMixer->deleteTrackName(name); -#endif + if (streamForcedToSpeaker(track->type())) { + mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_REMOVED); + } + } } -// ---------------------------------------------------------------------------- - -AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid) - : RefBase(), - mAudioFlinger(audioFlinger), - mMemoryDealer(new MemoryDealer(1024*1024)), - mPid(pid) +int AudioFlinger::MixerThread::getTrackName() { - // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer + return mAudioMixer->getTrackName(); } -AudioFlinger::Client::~Client() +void AudioFlinger::MixerThread::deleteTrackName(int name) { - mAudioFlinger->removeClient(mPid); + mAudioMixer->deleteTrackName(name); } -const sp<MemoryDealer>& AudioFlinger::Client::heap() const +size_t AudioFlinger::MixerThread::getOutputFrameCount() { - return mMemoryDealer; + return mOutput->bufferSize() / mOutput->channelCount() / sizeof(int16_t); } // ---------------------------------------------------------------------------- -AudioFlinger::TrackBase::TrackBase( - const sp<AudioFlinger>& audioFlinger, +AudioFlinger::MixerThread::TrackBase::TrackBase( + const sp<MixerThread>& mixerThread, const sp<Client>& client, int streamType, uint32_t sampleRate, @@ -1134,7 +1508,7 @@ AudioFlinger::TrackBase::TrackBase( int frameCount, const sp<IMemory>& sharedBuffer) : RefBase(), - mAudioFlinger(audioFlinger), + mMixerThread(mixerThread), mClient(client), mStreamType(streamType), mFrameCount(0), @@ -1143,7 +1517,7 @@ AudioFlinger::TrackBase::TrackBase( mFormat(format), mFlags(0) { - mName = audioFlinger->getTrackName(); + mName = mixerThread->getTrackName(); LOGV("TrackBase contructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid()); if (mName < 0) { LOGE("no more track names availlable"); @@ -1160,41 +1534,60 @@ AudioFlinger::TrackBase::TrackBase( 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; @@ -1202,7 +1595,7 @@ void AudioFlinger::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer) buffer->frameCount = 0; } -bool AudioFlinger::TrackBase::step() { +bool AudioFlinger::MixerThread::TrackBase::step() { bool result; audio_track_cblk_t* cblk = this->cblk(); @@ -1214,7 +1607,7 @@ bool AudioFlinger::TrackBase::step() { return result; } -void AudioFlinger::TrackBase::reset() { +void AudioFlinger::MixerThread::TrackBase::reset() { audio_track_cblk_t* cblk = this->cblk(); cblk->user = 0; @@ -1225,20 +1618,20 @@ void AudioFlinger::TrackBase::reset() { 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; @@ -1257,8 +1650,8 @@ void* AudioFlinger::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const // ---------------------------------------------------------------------------- -AudioFlinger::Track::Track( - const sp<AudioFlinger>& audioFlinger, +AudioFlinger::MixerThread::Track::Track( + const sp<MixerThread>& mixerThread, const sp<Client>& client, int streamType, uint32_t sampleRate, @@ -1266,7 +1659,7 @@ AudioFlinger::Track::Track( 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, sharedBuffer) { mVolume[0] = 1.0f; mVolume[1] = 1.0f; @@ -1274,23 +1667,23 @@ AudioFlinger::Track::Track( mSharedBuffer = sharedBuffer; } -AudioFlinger::Track::~Track() +AudioFlinger::MixerThread::Track::~Track() { wp<Track> weak(this); // never create a strong ref from the dtor mState = TERMINATED; - mAudioFlinger->removeTrack(weak, mName); + mMixerThread->removeTrack(weak, mName); } -void AudioFlinger::Track::destroy() +void AudioFlinger::MixerThread::Track::destroy() { - mAudioFlinger->destroyTrack(this); + mMixerThread->destroyTrack(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, @@ -1305,7 +1698,7 @@ void AudioFlinger::Track::dump(char* buffer, size_t size) 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; @@ -1345,53 +1738,54 @@ getNextBuffer_exit: 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), calling thread %d", mName, IPCThreadState::self()->getCallingPid()); - mAudioFlinger->addTrack(this); + LOGV("start(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType); + mMixerThread->addTrack(this); return NO_ERROR; } -void AudioFlinger::Track::stop() +void AudioFlinger::MixerThread::Track::stop() { - LOGV("stop(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid()); - Mutex::Autolock _l(mAudioFlinger->mLock); + LOGV("stop(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType); + Mutex::Autolock _l(mMixerThread->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), calling thread %d", mName, IPCThreadState::self()->getCallingPid()); - Mutex::Autolock _l(mAudioFlinger->mLock); + Mutex::Autolock _l(mMixerThread->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->mLock); if (mState != STOPPED && mState != PAUSED && mState != PAUSING) { return; } @@ -1407,7 +1801,7 @@ void AudioFlinger::Track::flush() 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. @@ -1422,12 +1816,12 @@ void AudioFlinger::Track::reset() } } -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; @@ -1435,7 +1829,289 @@ void AudioFlinger::Track::setVolume(float left, float right) // ---------------------------------------------------------------------------- -AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::Track>& track) +AudioFlinger::MixerThread::RecordTrack::RecordTrack( + const sp<MixerThread>& mixerThread, + const sp<Client>& client, + int streamType, + uint32_t sampleRate, + int format, + int channelCount, + int frameCount) + : TrackBase(mixerThread, client, streamType, sampleRate, format, + channelCount, frameCount, 0), + mOverflow(false) +{ +} + +AudioFlinger::MixerThread::RecordTrack::~RecordTrack() +{ + mMixerThread->deleteTrackName(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) { @@ -1496,7 +2172,7 @@ sp<IAudioRecord> AudioFlinger::openRecord( status_t *status) { sp<AudioRecordThread> thread; - sp<RecordTrack> recordTrack; + sp<MixerThread::RecordTrack> recordTrack; sp<RecordHandle> recordHandle; sp<Client> client; wp<Client> wclient; @@ -1523,12 +2199,6 @@ sp<IAudioRecord> AudioFlinger::openRecord( 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; @@ -1561,7 +2231,7 @@ sp<IAudioRecord> AudioFlinger::openRecord( frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount; // create new record track and pass to record thread - recordTrack = new RecordTrack(this, client, streamType, sampleRate, + recordTrack = new MixerThread::RecordTrack(mHardwareMixerThread, client, streamType, sampleRate, format, channelCount, frameCount); // return to handle to client @@ -1575,97 +2245,22 @@ Exit: 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->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) { @@ -1786,7 +2381,7 @@ bool AudioFlinger::AudioRecordThread::threadLoop() return false; } -status_t AudioFlinger::AudioRecordThread::start(RecordTrack* recordTrack) +status_t AudioFlinger::AudioRecordThread::start(MixerThread::RecordTrack* recordTrack) { LOGV("AudioRecordThread::start"); AutoMutex lock(&mLock); @@ -1807,7 +2402,7 @@ status_t AudioFlinger::AudioRecordThread::start(RecordTrack* recordTrack) 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())) { diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h index 38fa001..3b5932d 100644 --- a/libs/audioflinger/AudioFlinger.h +++ b/libs/audioflinger/AudioFlinger.h @@ -33,6 +33,7 @@ #include <utils/MemoryDealer.h> #include <utils/KeyedVector.h> #include <utils/SortedVector.h> +#include <utils/Vector.h> #include <hardware_legacy/AudioHardwareInterface.h> @@ -55,18 +56,13 @@ class AudioBuffer; static const nsecs_t kStandbyTimeInNsecs = seconds(3); -class AudioFlinger : public BnAudioFlinger, protected Thread, public IBinder::DeathRecipient +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, @@ -79,11 +75,11 @@ public: 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); @@ -108,6 +104,8 @@ public: 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); @@ -159,23 +157,26 @@ private: 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 - static bool streamDisablesA2dp(int streamType); - inline bool isA2dpEnabled() const { - return (mRequestedOutput == mA2dpOutput || - (mOutput && mOutput == mA2dpOutput)); - } void setA2dpEnabled(bool enable); #endif + static bool streamForcedToSpeaker(int streamType); + + // 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); // 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 --- @@ -194,168 +195,348 @@ private: }; - // --- 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 + }; + + TrackBase( const sp<MixerThread>& mixerThread, + const sp<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 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; + uint8_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); + ~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, - 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, + // 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( + const sp<AudioFlinger::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 wakeUp() { mWaitWorkCV.broadcast(); } + + void getTracks(SortedVector < sp<Track> >& tracks, + SortedVector < wp<Track> >& activeTracks); + void putTracks(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; - - Track(const Track&); - Track& operator = (const Track&); - - virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer); - - bool isMuted() const { - return (mMute || mAudioFlinger->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 + friend class AudioFlinger; + friend class Track; + friend class TrackBase; + friend class RecordTrack; + + MixerThread(const Client&); + MixerThread& operator = (const MixerThread&); + + 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); + int getTrackName(); + void deleteTrackName(int name); + void addActiveTrack(const wp<Track>& t); + void removeActiveTrack(const wp<Track>& t); + size_t getOutputFrameCount(); + + status_t dumpInternals(int fd, const Vector<String16>& args); + status_t dumpTracks(int fd, const Vector<String16>& args); + + sp<AudioFlinger> mAudioFlinger; + mutable Mutex mLock; + mutable Condition mWaitWorkCV; + 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; + }; + 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(); @@ -367,72 +548,20 @@ private: 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); - int getTrackName(); - void deleteTrackName(int name); - - 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(); @@ -440,7 +569,7 @@ private: 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 @@ -453,14 +582,14 @@ private: 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(); private: AudioRecordThread(); AudioHardwareInterface *mAudioHardware; - sp<RecordTrack> mRecordTrack; + sp<MixerThread::RecordTrack> mRecordTrack; Mutex mLock; Condition mWaitWorkCV; volatile bool mActive; @@ -468,48 +597,31 @@ private: }; friend class AudioRecordThread; + friend class MixerThread; - status_t startRecord(RecordTrack* recordTrack); - void stopRecord(RecordTrack* recordTrack); - - void notifyOutputChange_l(); + status_t startRecord(MixerThread::RecordTrack* recordTrack); + void stopRecord(MixerThread::RecordTrack* recordTrack); + + void handleOutputSwitch(); 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 mA2dpEnabledReq; mutable int mHardwareStatus; - nsecs_t mLastWriteTime; - int mNumWrites; - int mNumDelayedWrites; - bool mStandby; - bool mInWrite; - int mA2dpDisableCount; - bool mA2dpSuppressed; - bool mMusicMuteSaved; SortedVector< wp<IBinder> > mNotificationClients; + int mForcedSpeakerCount; + uint32_t mSavedRoute; + uint32_t mForcedRoute; + nsecs_t mRouteRestoreTime; + bool mMusicMuteSaved; }; // ---------------------------------------------------------------------------- diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk index 53ba3bc..496e271 100644 --- a/libs/surfaceflinger/Android.mk +++ b/libs/surfaceflinger/Android.mk @@ -16,9 +16,7 @@ LOCAL_SRC_FILES:= \ LayerBitmap.cpp \ LayerDim.cpp \ LayerOrientationAnim.cpp \ - LayerScreenshot.cpp \ OrientationAnimation.cpp \ - RFBServer.cpp \ SurfaceFlinger.cpp \ Tokenizer.cpp \ Transform.cpp \ diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp index 31e63ef..f65d669 100644 --- a/libs/surfaceflinger/Layer.cpp +++ b/libs/surfaceflinger/Layer.cpp @@ -186,7 +186,9 @@ void Layer::onDraw(const Region& clip) const copybit_device_t* copybit = mFlinger->getBlitEngine(); copybit->set_parameter(copybit, COPYBIT_TRANSFORM, getOrientation()); copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha); - copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE); + copybit->set_parameter(copybit, COPYBIT_DITHER, + s.flags & ISurfaceComposer::eLayerDither ? + COPYBIT_ENABLE : COPYBIT_DISABLE); region_iterator it(clip); err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it); diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp index 9277a64..0cf53f7 100644 --- a/libs/surfaceflinger/LayerBase.cpp +++ b/libs/surfaceflinger/LayerBase.cpp @@ -26,6 +26,8 @@ #include <GLES/gl.h> #include <GLES/glext.h> +#include <hardware/hardware.h> + #include "clz.h" #include "LayerBase.h" #include "LayerBlur.h" @@ -229,15 +231,10 @@ Point LayerBase::getPhysicalSize() const return Point(front.w, front.h); } -Transform LayerBase::getDrawingStateTransform() const -{ - return drawingState().transform; -} - void LayerBase::validateVisibility(const Transform& planeTransform) { const Layer::State& s(drawingState()); - const Transform tr(planeTransform * getDrawingStateTransform()); + const Transform tr(planeTransform * s.transform); const bool transformed = tr.transformed(); const Point size(getPhysicalSize()); @@ -420,7 +417,7 @@ void LayerBase::clearWithOpenGL(const Region& clip) const } 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(); @@ -492,6 +489,12 @@ void LayerBase::drawWithOpenGL(const Region& clip, 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 2377a14..a020f44 100644 --- a/libs/surfaceflinger/LayerBase.h +++ b/libs/surfaceflinger/LayerBase.h @@ -169,13 +169,6 @@ public: virtual void validateVisibility(const Transform& globalTransform); /** - * getDrawingStateTransform - returns the drawing state's transform. - * This is used in validateVisibility() and can be use to override or - * modify the transform (if so make sure to trigger a transaction). - */ - virtual Transform getDrawingStateTransform() const; - - /** * lockPageFlip - called each time the screen is redrawn and returns whether * the visible regions need to be recomputed (this is a fairly heavy * operation, so this should be set only if needed). Typically this is used @@ -200,10 +193,15 @@ public: * needsBlending - true if this surface needs blending */ virtual bool needsBlending() const { return false; } - + + /** + * 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 a - * screenshot to be taken, + * isSecure - true if this surface is secure, that is if it prevents + * screenshots or vns servers. */ virtual bool isSecure() const { return false; } @@ -222,7 +220,6 @@ public: } int32_t getOrientation() const { return mOrientation; } - bool transformed() const { return mTransformed; } int tx() const { return mLeft; } int ty() const { return mTop; } @@ -233,7 +230,9 @@ protected: 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; diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp index fc0a603..00fab70 100644 --- a/libs/surfaceflinger/LayerBuffer.cpp +++ b/libs/surfaceflinger/LayerBuffer.cpp @@ -103,15 +103,6 @@ void LayerBuffer::unregisterBuffers() source->unregisterBuffers(); } -Transform LayerBuffer::getDrawingStateTransform() const -{ - Transform tr(LayerBaseClient::getDrawingStateTransform()); - sp<Source> source(getSource()); - if (source != 0) - source->updateTransform(&tr); - return tr; -} - uint32_t LayerBuffer::doTransaction(uint32_t flags) { sp<Source> source(getSource()); @@ -141,6 +132,14 @@ void LayerBuffer::onDraw(const Region& clip) const } } +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 */ @@ -316,7 +315,8 @@ void LayerBuffer::Source::postBuffer(ssize_t offset) { } void LayerBuffer::Source::unregisterBuffers() { } -void LayerBuffer::Source::updateTransform(Transform* tr) const { +bool LayerBuffer::Source::transformed() const { + return mLayer.mTransformed; } // --------------------------------------------------------------------------- @@ -363,6 +363,7 @@ LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer, mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0); mBufferSize = info.getScanlineSize(buffers.hor_stride)*buffers.ver_stride; mLayer.forceVisibilityTransaction(); + } LayerBuffer::BufferSource::~BufferSource() @@ -419,15 +420,9 @@ void LayerBuffer::BufferSource::setBuffer(const sp<LayerBuffer::Buffer>& buffer) mBuffer = buffer; } -void LayerBuffer::BufferSource::updateTransform(Transform* tr) const +bool LayerBuffer::BufferSource::transformed() const { - uint32_t bufTransform = mBufferHeap.transform; - // TODO: handle all transforms - if (bufTransform == ISurface::BufferHeap::ROT_90) { - Transform rot90; - rot90.set(0, -1, 1, 0); - *tr = (*tr) * rot90; - } + return mBufferHeap.transform ? true : Source::transformed(); } void LayerBuffer::BufferSource::onDraw(const Region& clip) const @@ -476,7 +471,7 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const 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); } @@ -506,10 +501,23 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const 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, COPYBIT_ENABLE); @@ -536,10 +544,11 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const 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 5532532..2dc77f1 100644 --- a/libs/surfaceflinger/LayerBuffer.h +++ b/libs/surfaceflinger/LayerBuffer.h @@ -46,7 +46,7 @@ class LayerBuffer : public LayerBaseClient virtual void onVisibilityResolved(const Transform& planeTransform); virtual void postBuffer(ssize_t offset); virtual void unregisterBuffers(); - virtual void updateTransform(Transform* tr) const; + virtual bool transformed() const; protected: LayerBuffer& mLayer; }; @@ -68,7 +68,7 @@ public: virtual void onDraw(const Region& clip) const; virtual uint32_t doTransaction(uint32_t flags); virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion); - virtual Transform getDrawingStateTransform() const; + virtual bool transformed() const; status_t registerBuffers(const ISurface::BufferHeap& buffers); void postBuffer(ssize_t offset); @@ -116,10 +116,10 @@ private: sp<Buffer> getBuffer() const; void setBuffer(const sp<Buffer>& buffer); - virtual void updateTransform(Transform* tr) const; 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<Buffer> mBuffer; diff --git a/libs/surfaceflinger/LayerOrientationAnim.cpp b/libs/surfaceflinger/LayerOrientationAnim.cpp index 46b3b19..2b72d7c 100644 --- a/libs/surfaceflinger/LayerOrientationAnim.cpp +++ b/libs/surfaceflinger/LayerOrientationAnim.cpp @@ -84,7 +84,7 @@ Point LayerOrientationAnim::getPhysicalSize() const void LayerOrientationAnim::validateVisibility(const Transform&) { const Layer::State& s(drawingState()); - const Transform tr(getDrawingStateTransform()); + const Transform tr(s.transform); const Point size(getPhysicalSize()); uint32_t w = size.x; uint32_t h = size.y; diff --git a/libs/surfaceflinger/LayerScreenshot.cpp b/libs/surfaceflinger/LayerScreenshot.cpp deleted file mode 100644 index 40c47b0..0000000 --- a/libs/surfaceflinger/LayerScreenshot.cpp +++ /dev/null @@ -1,110 +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 "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 "LayerScreenshot.h" -#include "SurfaceFlinger.h" -#include "DisplayHardware/DisplayHardware.h" - -namespace android { -// --------------------------------------------------------------------------- - -const uint32_t LayerScreenshot::typeInfo = LayerBase::typeInfo | 0x40; -const char* const LayerScreenshot::typeID = "LayerScreenshot"; - -// --------------------------------------------------------------------------- - -LayerScreenshot::LayerScreenshot(SurfaceFlinger* flinger, DisplayID display) - : LayerBase(flinger, display), mReply(0) -{ -} - -LayerScreenshot::~LayerScreenshot() -{ -} - -void LayerScreenshot::onDraw(const Region& clip) const -{ - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - copybit_image_t dst; - hw.getDisplaySurface(&dst); - if (dst.base != 0) { - uint8_t const* src = (uint8_t const*)(intptr_t(dst.base) + dst.offset); - const int fbWidth = dst.w; - const int fbHeight = dst.h; - const int fbFormat = dst.format; - - int x = mTransformedBounds.left; - int y = mTransformedBounds.top; - int w = mTransformedBounds.width(); - int h = mTransformedBounds.height(); - Parcel* const reply = mReply; - if (reply) { - const size_t Bpp = bytesPerPixel(fbFormat); - const size_t size = w * h * Bpp; - int32_t cfg = SkBitmap::kNo_Config; - switch (fbFormat) { - case PIXEL_FORMAT_RGBA_4444: cfg = SkBitmap::kARGB_4444_Config; - case PIXEL_FORMAT_RGBA_8888: cfg = SkBitmap::kARGB_8888_Config; - case PIXEL_FORMAT_RGB_565: cfg = SkBitmap::kRGB_565_Config; - case PIXEL_FORMAT_A_8: cfg = SkBitmap::kA8_Config; - } - reply->writeInt32(0); - reply->writeInt32(cfg); - reply->writeInt32(w); - reply->writeInt32(h); - reply->writeInt32(w * Bpp); - void* data = reply->writeInplace(size); - if (data) { - uint8_t* d = (uint8_t*)data; - uint8_t const* s = src + (x + y*fbWidth) * Bpp; - if (w == fbWidth) { - memcpy(d, s, w*h*Bpp); - } else { - for (int y=0 ; y<h ; y++) { - memcpy(d, s, w*Bpp); - d += w*Bpp; - s += fbWidth*Bpp; - } - } - } - } - } - mCV.broadcast(); -} - -void LayerScreenshot::takeScreenshot(Mutex& lock, Parcel* reply) -{ - mReply = reply; - mCV.wait(lock); -} - -// --------------------------------------------------------------------------- - -}; // namespace android 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/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 4e457c9..900282a 100644 --- a/libs/surfaceflinger/SurfaceFlinger.cpp +++ b/libs/surfaceflinger/SurfaceFlinger.cpp @@ -53,21 +53,14 @@ #include "LayerDim.h" #include "LayerBitmap.h" #include "LayerOrientationAnim.h" -#include "LayerScreenshot.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 { @@ -460,9 +453,6 @@ status_t SurfaceFlinger::readyToRun() if (mDebugNoBootAnimation == false) mBootAnimation = new BootAnimation(this); - if (ENABLE_VNC_SERVER) - mRFBServer = new RFBServer(w, h, f); - return NO_ERROR; } @@ -572,18 +562,6 @@ void SurfaceFlinger::postFramebuffer() 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(); @@ -1571,55 +1549,17 @@ status_t SurfaceFlinger::onTransact( 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; @@ -1652,8 +1592,8 @@ status_t SurfaceFlinger::onTransact( 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; @@ -1669,13 +1609,12 @@ status_t SurfaceFlinger::onTransact( 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; @@ -1829,10 +1768,33 @@ void GraphicPlane::setTransform(const Transform& tr) { mGlobalTransform = mOrientationTransform * mTransform; } -status_t GraphicPlane::setOrientation(int orientation) -{ +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) +{ const DisplayHardware& hw(displayHardware()); const float w = hw.getWidth(); const float h = hw.getHeight(); @@ -1846,30 +1808,21 @@ status_t GraphicPlane::setOrientation(int orientation) // 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 8e5fd88..f7d7764 100644 --- a/libs/surfaceflinger/SurfaceFlinger.h +++ b/libs/surfaceflinger/SurfaceFlinger.h @@ -58,7 +58,6 @@ class Layer; class LayerBuffer; class LayerOrientationAnim; class OrientationAnimation; -class RFBServer; class SurfaceHeapManager; typedef int32_t ClientID; @@ -112,6 +111,8 @@ private: class GraphicPlane { public: + static status_t orientationToTransfrom(int orientation, int w, int h, + Transform* tr); GraphicPlane(); ~GraphicPlane(); @@ -344,7 +345,6 @@ private: sp<GPUHardwareInterface> mGPU; GLuint mWormholeTexName; sp<BootAnimation> mBootAnimation; - sp<RFBServer> mRFBServer; nsecs_t mBootTime; // Can only accessed from the main thread, these members diff --git a/libs/ui/ISurface.cpp b/libs/ui/ISurface.cpp index abd3634..d5e9f81 100644 --- a/libs/ui/ISurface.cpp +++ b/libs/ui/ISurface.cpp @@ -37,7 +37,7 @@ 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), heap(heap) + format(format), transform(0), flags(0), heap(heap) { } |