auto import from //branches/cupcake/...@131421
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 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 @@
// ----------------------------------------------------------------------------
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 @@
// 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 @@
property_get("ro.audio.silent", value, "0");
if (atoi(value)) {
LOGD("Silence is golden");
- mMasterMute = true;
+ setMasterMute(true);
}
}
@@ -172,64 +186,36 @@
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();
+#endif
}
-void AudioFlinger::doSetOutput(AudioStreamOut* output)
-{
- mSampleRate = output->sampleRate();
- mChannelCount = output->channelCount();
-
- // FIXME - Current mixer implementation only supports stereo output
- if (mChannelCount == 1) {
- LOGE("Invalid audio hardware channel count");
- }
- mFormat = output->format();
- mFrameCount = getOutputFrameCount(output);
- mAudioMixer = (output == mA2dpOutput ? mA2dpAudioMixer : mHardwareAudioMixer);
- mOutput = output;
- notifyOutputChange_l();
-}
-
-size_t AudioFlinger::getOutputFrameCount(AudioStreamOut* output)
-{
- return output->bufferSize() / output->channelCount() / sizeof(int16_t);
-}
#ifdef WITH_A2DP
-bool AudioFlinger::streamDisablesA2dp(int streamType)
-{
- return (streamType == AudioTrack::SYSTEM ||
- streamType == AudioTrack::RING ||
- streamType == AudioTrack::ALARM ||
- streamType == AudioTrack::VOICE_CALL ||
- streamType == AudioTrack::BLUETOOTH_SCO ||
- streamType == AudioTrack::NOTIFICATION);
-}
-
void AudioFlinger::setA2dpEnabled(bool enable)
{
- if (enable) {
- LOGD("set output to A2DP\n");
- setOutput(mA2dpOutput);
- } else {
- LOGD("set output to hardware audio\n");
- setOutput(mHardwareOutput);
- }
+ LOGV_IF(enable, "set output to A2DP\n");
+ LOGV_IF(!enable, "set output to hardware audio\n");
+
+ mA2dpEnabledReq = enable;
+ mA2dpMixerThread->wakeUp();
}
#endif // WITH_A2DP
+bool AudioFlinger::streamForcedToSpeaker(int streamType)
+{
+ // NOTE that streams listed here must not be routed to A2DP by default:
+ // AudioSystem::routedToA2dpOutput(streamType) == false
+ return (streamType == AudioSystem::RING ||
+ streamType == AudioSystem::ALARM ||
+ streamType == AudioSystem::NOTIFICATION);
+}
+
status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
@@ -251,40 +237,6 @@
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 @@
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 @@
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 @@
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;
-}
-
-void AudioFlinger::onFirstRef()
-{
- run("AudioFlinger", ANDROID_PRIORITY_URGENT_AUDIO);
-}
-
// IAudioFlinger interface
+
+
sp<IAudioTrack> AudioFlinger::createTrack(
pid_t pid,
int streamType,
@@ -572,34 +299,21 @@
const sp<IMemory>& sharedBuffer,
status_t *status)
{
- sp<Track> track;
+ sp<MixerThread::Track> track;
sp<TrackHandle> trackHandle;
sp<Client> client;
wp<Client> wclient;
status_t lStatus;
- if (streamType >= AudioTrack::NUM_STREAM_TYPES) {
+ if (streamType >= AudioSystem::NUM_STREAM_TYPES) {
LOGE("invalid stream type");
lStatus = BAD_VALUE;
goto Exit;
}
- // Resampler implementation limits input sampling rate to 2 x output sampling rate.
- if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) {
- LOGE("Sample rate out of range: %d", sampleRate);
- lStatus = BAD_VALUE;
- goto Exit;
- }
-
{
Mutex::Autolock _l(mLock);
- if (mSampleRate == 0) {
- LOGE("Audio driver not initialized.");
- lStatus = NO_INIT;
- goto Exit;
- }
-
wclient = mClients.valueFor(pid);
if (wclient != NULL) {
@@ -608,13 +322,20 @@
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 @@
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 @@
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 @@
}
#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 @@
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 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 @@
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 @@
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 @@
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 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 @@
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 @@
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 @@
}
}
-// 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 @@
}
// 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 @@
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::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 @@
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::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");
+
+ // Force routing to speaker for certain stream types
+ // The forced routing to speaker is managed by hardware mixer
+ if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+ sp<Track> track = t.promote();
+ if (track == NULL) return;
+
+ if (streamForcedToSpeaker(track->type())) {
+ mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_REMOVED);
+ }
}
-#endif
}
-int AudioFlinger::getTrackName()
+int AudioFlinger::MixerThread::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;
+ return mAudioMixer->getTrackName();
}
-void AudioFlinger::deleteTrackName(int name)
+void AudioFlinger::MixerThread::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
+ mAudioMixer->deleteTrackName(name);
+}
+
+size_t AudioFlinger::MixerThread::getOutputFrameCount()
+{
+ return mOutput->bufferSize() / mOutput->channelCount() / sizeof(int16_t);
}
// ----------------------------------------------------------------------------
-AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
- : RefBase(),
- mAudioFlinger(audioFlinger),
- mMemoryDealer(new MemoryDealer(1024*1024)),
- mPid(pid)
-{
- // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
-}
-
-AudioFlinger::Client::~Client()
-{
- mAudioFlinger->removeClient(mPid);
-}
-
-const sp<MemoryDealer>& AudioFlinger::Client::heap() const
-{
- return mMemoryDealer;
-}
-
-// ----------------------------------------------------------------------------
-
-AudioFlinger::TrackBase::TrackBase(
- const sp<AudioFlinger>& audioFlinger,
+AudioFlinger::MixerThread::TrackBase::TrackBase(
+ const sp<MixerThread>& mixerThread,
const sp<Client>& client,
int streamType,
uint32_t sampleRate,
@@ -1134,7 +1508,7 @@
int frameCount,
const sp<IMemory>& sharedBuffer)
: RefBase(),
- mAudioFlinger(audioFlinger),
+ mMixerThread(mixerThread),
mClient(client),
mStreamType(streamType),
mFrameCount(0),
@@ -1143,7 +1517,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// ----------------------------------------------------------------------------
-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 @@
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 @@
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 @@
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 @@
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 @@
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::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 @@
// ----------------------------------------------------------------------------
-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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
};
- // --- 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,
+ // 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);
- ~TrackBase();
+ const sp<IMemory>& sharedBuffer,
+ status_t *status);
- virtual status_t start() = 0;
- virtual void stop() = 0;
- sp<IMemory> getCblk() const;
-
- protected:
- friend class AudioFlinger;
- friend class RecordHandle;
- friend class AudioRecordThread;
-
- TrackBase(const TrackBase&);
- TrackBase& operator = (const TrackBase&);
-
- virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
- virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
-
- audio_track_cblk_t* cblk() const {
- return mCblk;
- }
-
- int type() const {
- return mStreamType;
- }
-
- int format() const {
- return mFormat;
- }
-
- int channelCount() const ;
-
- int sampleRate() const;
-
- void* getBuffer(uint32_t offset, uint32_t frames) const;
-
- int name() const {
- return mName;
- }
-
- bool isStopped() const {
- return mState == STOPPED;
- }
-
- bool isTerminated() const {
- return mState == TERMINATED;
- }
-
- bool step();
- void reset();
-
- sp<AudioFlinger> mAudioFlinger;
- sp<Client> mClient;
- sp<IMemory> mCblkMemory;
- audio_track_cblk_t* mCblk;
- int mStreamType;
- void* mBuffer;
- void* mBufferEnd;
- uint32_t mFrameCount;
- int mName;
- // we don't really need a lock for these
- int mState;
- int mClientTid;
- uint8_t mFormat;
- uint8_t mFlags;
- };
-
- // playback track
- class Track : public TrackBase {
- public:
- Track( const sp<AudioFlinger>& audioFlinger,
- const sp<Client>& client,
- int streamType,
- uint32_t sampleRate,
- int format,
- int channelCount,
- int frameCount,
- const sp<IMemory>& sharedBuffer);
- ~Track();
-
- void dump(char* buffer, size_t size);
- virtual status_t start();
- virtual void stop();
- void pause();
-
- void flush();
- void destroy();
- void mute(bool);
- void setVolume(float left, float right);
+ 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;
+ 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();
- Track(const Track&);
- Track& operator = (const Track&);
+ status_t dumpInternals(int fd, const Vector<String16>& args);
+ status_t dumpTracks(int fd, const Vector<String16>& args);
+
+ sp<AudioFlinger> mAudioFlinger;
+ 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;
+ };
- 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 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 @@
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 @@
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 @@
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 @@
};
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 @@
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 @@
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 @@
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::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 @@
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 @@
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 @@
* needsBlending - true if this surface needs blending
*/
virtual bool needsBlending() const { return false; }
-
+
/**
- * isSecure - true if this surface is secure, that is if it prevents a
- * screenshot to be taken,
+ * transformed -- true is this surface needs a to be transformed
+ */
+ virtual bool transformed() const { return mTransformed; }
+
+ /**
+ * isSecure - true if this surface is secure, that is if it prevents
+ * screenshots or vns servers.
*/
virtual bool isSecure() const { return false; }
@@ -222,7 +220,6 @@
}
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 @@
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 @@
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 @@
}
}
+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::unregisterBuffers() {
}
-void LayerBuffer::Source::updateTransform(Transform* tr) const {
+bool LayerBuffer::Source::transformed() const {
+ return mLayer.mTransformed;
}
// ---------------------------------------------------------------------------
@@ -363,6 +363,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
if (mDebugNoBootAnimation == false)
mBootAnimation = new BootAnimation(this);
- if (ENABLE_VNC_SERVER)
- mRFBServer = new RFBServer(w, h, f);
-
return NO_ERROR;
}
@@ -572,18 +562,6 @@
debugShowFPS();
}
- if (UNLIKELY(ENABLE_VNC_SERVER &&
- mRFBServer!=0 && mRFBServer->isConnected())) {
- if (!mSecureFrameBuffer) {
- GGLSurface fb;
- // backbufer, is going to become the front buffer really soon
- hw.getDisplaySurface(&fb);
- if (LIKELY(fb.data != 0)) {
- mRFBServer->frameBufferUpdated(fb, mInvalidRegion);
- }
- }
- }
-
hw.flip(mInvalidRegion);
mInvalidRegion.clear();
@@ -1571,55 +1549,17 @@
status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
- if (code == 1012) {
- // take screen-shot of the front buffer
- if (UNLIKELY(checkCallingPermission(
- String16("android.permission.READ_FRAME_BUFFER")) == false))
- { // not allowed
- LOGE("Permission Denial: "
- "can't take screenshots from pid=%d, uid=%d\n",
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid());
- return PERMISSION_DENIED;
- }
-
- if (UNLIKELY(mSecureFrameBuffer)) {
- LOGE("A secure window is on screen: "
- "can't take screenshots from pid=%d, uid=%d\n",
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid());
- return PERMISSION_DENIED;
- }
-
- LOGI("Taking a screenshot...");
-
- LayerScreenshot* l = new LayerScreenshot(this, 0);
-
- Mutex::Autolock _l(mStateLock);
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
- l->initStates(hw.getWidth(), hw.getHeight(), 0);
- l->setLayer(INT_MAX);
-
- addLayer_l(l);
- setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
-
- l->takeScreenshot(mStateLock, reply);
-
- removeLayer_l(l);
- setTransactionFlags(eTransactionNeeded);
- return NO_ERROR;
- } else {
- // HARDWARE_TEST stuff...
- if (UNLIKELY(checkCallingPermission(
- String16("android.permission.HARDWARE_TEST")) == false))
- { // not allowed
- LOGE("Permission Denial: pid=%d, uid=%d\n",
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid());
- return PERMISSION_DENIED;
- }
- int n;
- switch (code) {
+ // HARDWARE_TEST stuff...
+ if (UNLIKELY(checkCallingPermission(
+ String16("android.permission.HARDWARE_TEST")) == false))
+ { // not allowed
+ LOGE("Permission Denial: pid=%d, uid=%d\n",
+ IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid());
+ return PERMISSION_DENIED;
+ }
+ int n;
+ switch (code) {
case 1000: // SHOW_CPU
n = data.readInt32();
mDebugCpu = n ? 1 : 0;
@@ -1652,8 +1592,8 @@
const DisplayHardware& hw(graphicPlane(0).displayHardware());
mDirtyRegion.set(hw.bounds()); // careful that's not thread-safe
signalEvent();
- }
- return NO_ERROR;
+ }
+ return NO_ERROR;
case 1005: // ask GPU revoke
mGPU->friendlyRevoke();
return NO_ERROR;
@@ -1669,13 +1609,12 @@
reply->writeInt32(mDebugRegion);
reply->writeInt32(mDebugBackground);
return NO_ERROR;
- case 1013: { // screenshot
+ case 1013: {
Mutex::Autolock _l(mStateLock);
const DisplayHardware& hw(graphicPlane(0).displayHardware());
reply->writeInt32(hw.getPageFlipCount());
}
return NO_ERROR;
- }
}
}
return err;
@@ -1829,10 +1768,33 @@
mGlobalTransform = mOrientationTransform * mTransform;
}
+status_t GraphicPlane::orientationToTransfrom(
+ int orientation, int w, int h, Transform* tr)
+{
+ float a, b, c, d, x, y;
+ switch (orientation) {
+ case ISurfaceComposer::eOrientationDefault:
+ a=1; b=0; c=0; d=1; x=0; y=0;
+ break;
+ case ISurfaceComposer::eOrientation90:
+ a=0; b=-1; c=1; d=0; x=w; y=0;
+ break;
+ case ISurfaceComposer::eOrientation180:
+ a=-1; b=0; c=0; d=-1; x=w; y=h;
+ break;
+ case ISurfaceComposer::eOrientation270:
+ a=0; b=1; c=-1; d=0; x=0; y=h;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+ tr->set(a, b, c, d);
+ tr->set(x, y);
+ return NO_ERROR;
+}
+
status_t GraphicPlane::setOrientation(int orientation)
{
- float a, b, c, d, x, y;
-
const DisplayHardware& hw(displayHardware());
const float w = hw.getWidth();
const float h = hw.getHeight();
@@ -1846,30 +1808,21 @@
// If the rotation can be handled in hardware, this is where
// the magic should happen.
-
- switch (orientation) {
- case ISurfaceComposer::eOrientation90:
- a=0; b=-1; c=1; d=0; x=w; y=0;
- break;
- case ISurfaceComposer::eOrientation180:
- a=-1; b=0; c=0; d=-1; x=w; y=h;
- break;
- case ISurfaceComposer::eOrientation270:
- a=0; b=1; c=-1; d=0; x=0; y=h;
- break;
- case 42: {
+ if (UNLIKELY(orientation == 42)) {
+ float a, b, c, d, x, y;
const float r = (3.14159265f / 180.0f) * 42.0f;
const float si = sinf(r);
const float co = cosf(r);
a=co; b=-si; c=si; d=co;
x = si*(h*0.5f) + (1-co)*(w*0.5f);
y =-si*(w*0.5f) + (1-co)*(h*0.5f);
- } break;
- default:
- return BAD_VALUE;
+ mOrientationTransform.set(a, b, c, d);
+ mOrientationTransform.set(x, y);
+ } else {
+ GraphicPlane::orientationToTransfrom(orientation, w, h,
+ &mOrientationTransform);
}
- mOrientationTransform.set(a, b, c, d);
- mOrientationTransform.set(x, y);
+
mGlobalTransform = mOrientationTransform * mTransform;
return NO_ERROR;
}
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index 8e5fd88..f7d7764 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -58,7 +58,6 @@
class LayerBuffer;
class LayerOrientationAnim;
class OrientationAnimation;
-class RFBServer;
class SurfaceHeapManager;
typedef int32_t ClientID;
@@ -112,6 +111,8 @@
class GraphicPlane
{
public:
+ static status_t orientationToTransfrom(int orientation, int w, int h,
+ Transform* tr);
GraphicPlane();
~GraphicPlane();
@@ -344,7 +345,6 @@
sp<GPUHardwareInterface> mGPU;
GLuint mWormholeTexName;
sp<BootAnimation> mBootAnimation;
- sp<RFBServer> mRFBServer;
nsecs_t mBootTime;
// Can only accessed from the main thread, these members
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 @@
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)
{
}