diff options
| author | 2008-12-19 08:31:54 -0800 | |
|---|---|---|
| committer | 2008-12-19 08:31:54 -0800 | |
| commit | 772a89695f179b51d16b26c1b0d946aa3e850e70 (patch) | |
| tree | 9a9fdadd1301625f875a3c126c986c79e3363ac4 /libs/audioflinger/AudioFlinger.cpp | |
| parent | d34e59679f6a98e9e67ef4bd18da6e5a86d386bc (diff) | |
| parent | e09fd9e819c23dc90bca68375645e15544861330 (diff) | |
Merge commit 'remotes/korg/cupcake'
Conflicts:
	core/java/com/android/internal/app/AlertController.java
	core/res/res/values/strings.xml
	media/java/android/media/AudioSystem.java
	services/java/com/android/server/LocationManagerService.java
Diffstat (limited to 'libs/audioflinger/AudioFlinger.cpp')
| -rw-r--r-- | libs/audioflinger/AudioFlinger.cpp | 710 | 
1 files changed, 461 insertions, 249 deletions
| diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp index fb2162960b..53b18ad1a0 100644 --- a/libs/audioflinger/AudioFlinger.cpp +++ b/libs/audioflinger/AudioFlinger.cpp @@ -31,6 +31,8 @@  #include <utils/String16.h>  #include <utils/threads.h> +#include <cutils/properties.h> +  #include <media/AudioTrack.h>  #include <media/AudioRecord.h> @@ -41,9 +43,13 @@  #include "AudioMixer.h"  #include "AudioFlinger.h" +#ifdef WITH_A2DP +#include "A2dpAudioInterface.h" +#endif +  namespace android { -static const nsecs_t kStandbyTimeInNsecs = seconds(3); +//static const nsecs_t kStandbyTimeInNsecs = seconds(3);  static const unsigned long kBufferRecoveryInUsecs = 2000;  static const unsigned long kMaxBufferRecoveryInUsecs = 20000;  static const float MAX_GAIN = 4096.0f; @@ -93,8 +99,9 @@ static bool settingsAllowed() {  AudioFlinger::AudioFlinger()      : BnAudioFlinger(), Thread(false), -        mMasterVolume(0), mMasterMute(true), -        mAudioMixer(0), mAudioHardware(0), mOutput(0), mAudioRecordThread(0), +        mMasterVolume(0), mMasterMute(true), mHardwareAudioMixer(0), mA2dpAudioMixer(0), +        mAudioMixer(0), mAudioHardware(0), mA2dpAudioInterface(0), +        mHardwareOutput(0), mA2dpOutput(0), mOutput(0), mAudioRecordThread(0),          mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0),          mMixBuffer(0), mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0),          mStandby(false), mInWrite(false) @@ -105,17 +112,14 @@ AudioFlinger::AudioFlinger()      if (mAudioHardware->initCheck() == NO_ERROR) {          // open 16-bit output stream for s/w mixer          mHardwareStatus = AUDIO_HW_OUTPUT_OPEN; -        mOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT); +        status_t status; +        mHardwareOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);          mHardwareStatus = AUDIO_HW_IDLE; -        if (mOutput) { -            mSampleRate = mOutput->sampleRate(); -            mChannelCount = mOutput->channelCount(); -            mFormat = mOutput->format(); -            mMixBufferSize = mOutput->bufferSize(); -            mFrameCount = mMixBufferSize / mChannelCount / sizeof(int16_t); -            mMixBuffer = new int16_t[mFrameCount * mChannelCount]; -            memset(mMixBuffer, 0, mMixBufferSize); -            mAudioMixer = new AudioMixer(mFrameCount, mSampleRate); +        if (mHardwareOutput) { +            mSampleRate = mHardwareOutput->sampleRate(); +            mHardwareAudioMixer = new AudioMixer(getOutputFrameCount(mHardwareOutput), mSampleRate); +            setOutput(mHardwareOutput); +              // FIXME - this should come from settings              setMasterVolume(1.0f);              setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL); @@ -124,20 +128,87 @@ AudioFlinger::AudioFlinger()              setMode(AudioSystem::MODE_NORMAL);              mMasterMute = false;          } else { -            LOGE("Failed to initialize output stream"); +            LOGE("Failed to initialize output stream, status: %d", status);          } -    } else { +         +#ifdef WITH_A2DP +        // Create A2DP interface +        mA2dpAudioInterface = new A2dpAudioInterface(); +        mA2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);        +        mA2dpAudioMixer = new AudioMixer(getOutputFrameCount(mA2dpOutput), mA2dpOutput->sampleRate()); + +        // create a buffer big enough for both hardware and A2DP audio output. +        size_t hwFrameCount = getOutputFrameCount(mHardwareOutput); +        size_t a2dpFrameCount = getOutputFrameCount(mA2dpOutput); +        size_t frameCount = (hwFrameCount > a2dpFrameCount ? hwFrameCount : a2dpFrameCount); +#else +        size_t frameCount = getOutputFrameCount(mHardwareOutput); +#endif +        // FIXME - Current mixer implementation only supports stereo output: Always +        // Allocate a stereo buffer even if HW output is mono. +        mMixBuffer = new int16_t[frameCount * 2]; +        memset(mMixBuffer, 0, frameCount * 2 * sizeof(int16_t)); +         +        // Start record thread +        mAudioRecordThread = new AudioRecordThread(mAudioHardware); +        if (mAudioRecordThread != 0) { +            mAudioRecordThread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO);             +        } +     } else {          LOGE("Couldn't even initialize the stubbed audio hardware!");      } + +    char value[PROPERTY_VALUE_MAX]; +    // FIXME: What property should this be??? +    property_get("ro.audio.silent", value, "0"); +    if (atoi(value)) { +        LOGD("Silence is golden"); +        mMasterMute = true; +    }  }  AudioFlinger::~AudioFlinger()  { +    if (mAudioRecordThread != 0) { +        mAudioRecordThread->exit(); +        mAudioRecordThread.clear();         +    }      delete mOutput; +    delete mA2dpOutput;      delete mAudioHardware; +    delete mA2dpAudioInterface;      delete [] mMixBuffer; -    delete mAudioMixer; -    mAudioRecordThread.clear(); +    delete mHardwareAudioMixer; +    delete mA2dpAudioMixer; +} +  +void AudioFlinger::setOutput(AudioStreamOut* output) +{ +    // lock on mOutputLock to prevent threadLoop() from starving us +    Mutex::Autolock _l2(mOutputLock); +     +    // to synchronize with threadLoop() +    Mutex::Autolock _l(mLock); + +    if (mOutput != output) { +        mSampleRate = output->sampleRate(); +        mChannelCount = output->channelCount(); +     +        // FIXME - Current mixer implementation only supports stereo output +        if (mChannelCount == 1) { +            LOGE("Invalid audio hardware channel count"); +        } +        mFormat = output->format(); +        mFrameCount = getOutputFrameCount(output); +                 +        mAudioMixer = (output == mA2dpOutput ? mA2dpAudioMixer : mHardwareAudioMixer); +        mOutput = output; +    } +} + +size_t AudioFlinger::getOutputFrameCount(AudioStreamOut* output)  +{ +    return output->bufferSize() / output->channelCount() / sizeof(int16_t);  }  status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args) @@ -201,8 +272,8 @@ status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)      const size_t SIZE = 256;      char buffer[SIZE];      String8 result; -     -    snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", audioMixer().trackNames()); + +    snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", audioMixer()->trackNames());      result.append(buffer);      snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));      result.append(buffer); @@ -254,17 +325,26 @@ status_t AudioFlinger::dump(int fd, const Vector<String16>& args)  // Thread virtuals  bool AudioFlinger::threadLoop()  { -    nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2;      unsigned long sleepTime = kBufferRecoveryInUsecs; -    const size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t);      int16_t* curBuf = mMixBuffer;      Vector< sp<Track> > tracksToRemove; -    size_t enabledTracks; +    size_t enabledTracks = 0;      nsecs_t standbyTime = systemTime(); +    AudioMixer* mixer = 0; +    size_t frameCount = 0; +    int channelCount = 0; +    uint32_t sampleRate = 0; +    AudioStreamOut* output = 0;      do {          enabledTracks = 0; -        { // scope for the lock +        { // scope for the mLock +         +            // locking briefly on the secondary mOutputLock is necessary to avoid +            // having this thread starve the thread that called setOutput() +            mOutputLock.lock(); +            mOutputLock.unlock(); +              Mutex::Autolock _l(mLock);              const SortedVector< wp<Track> >& activeTracks = mActiveTracks; @@ -286,6 +366,15 @@ bool AudioFlinger::threadLoop()                  continue;              } +            // get active mixer and output parameter while the lock is held and keep them +            // consistent till the next loop. +             +            mixer = audioMixer(); +            frameCount = mFrameCount; +            channelCount = mChannelCount; +            sampleRate = mSampleRate; +            output = mOutput; +                          // find out which tracks need to be processed              size_t count = activeTracks.size();              for (size_t i=0 ; i<count ; i++) { @@ -294,13 +383,11 @@ bool AudioFlinger::threadLoop()                  Track* const track = t.get();                  audio_track_cblk_t* cblk = track->cblk(); -                uint32_t u = cblk->user; -                uint32_t s = cblk->server;                  // The first time a track is added we wait                  // for all its buffers to be filled before processing it -                audioMixer().setActiveTrack(track->name()); -                if ((u > s) && (track->isReady(u, s) || track->isStopped()) && +                mixer->setActiveTrack(track->name()); +                if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&                          !track->isPaused())                  {                      //LOGD("u=%08x, s=%08x [OK]", u, s); @@ -325,9 +412,8 @@ bool AudioFlinger::threadLoop()                      }                      // XXX: these things DON'T need to be done each time -                    AudioMixer& mixer(audioMixer()); -                    mixer.setBufferProvider(track); -                    mixer.enable(AudioMixer::MIXING); +                    mixer->setBufferProvider(track); +                    mixer->enable(AudioMixer::MIXING);                      int param;                      if ( track->mFillingUpStatus == Track::FS_FILLED) { @@ -342,15 +428,15 @@ bool AudioFlinger::threadLoop()                      } else {                          param = AudioMixer::RAMP_VOLUME;                      } -                    mixer.setParameter(param, AudioMixer::VOLUME0, left); -                    mixer.setParameter(param, AudioMixer::VOLUME1, right); -                    mixer.setParameter( +                    mixer->setParameter(param, AudioMixer::VOLUME0, left); +                    mixer->setParameter(param, AudioMixer::VOLUME1, right); +                    mixer->setParameter(                          AudioMixer::TRACK,                          AudioMixer::FORMAT, track->format()); -                    mixer.setParameter( +                    mixer->setParameter(                          AudioMixer::TRACK,                          AudioMixer::CHANNEL_COUNT, track->channelCount()); -                    mixer.setParameter( +                    mixer->setParameter(                          AudioMixer::RESAMPLE,                          AudioMixer::SAMPLE_RATE,                          int(cblk->sampleRate)); @@ -361,8 +447,7 @@ bool AudioFlinger::threadLoop()                  } else {                      //LOGD("u=%08x, s=%08x [NOT READY]", u, s);                      if (track->isStopped()) { -                        track->mFillingUpStatus = Track::FS_FILLING; -                        track->mFlags = 0;     +                        track->reset();                      }                      if (track->isTerminated() || track->isStopped() || track->isPaused()) {                          // We have consumed all the buffers of this track. @@ -378,7 +463,7 @@ bool AudioFlinger::threadLoop()                          }                      }                      // LOGV("disable(%d)", track->name()); -                    audioMixer().disable(AudioMixer::MIXING); +                    mixer->disable(AudioMixer::MIXING);                  }              } @@ -390,26 +475,27 @@ bool AudioFlinger::threadLoop()                      mActiveTracks.remove(track);                      if (track->isTerminated()) {                          mTracks.remove(track); -                        audioMixer().deleteTrackName(track->mName); +                        mixer->deleteTrackName(track->mName);                      }                  } -            } -        } - +            }   +       }          if (LIKELY(enabledTracks)) {              // mix buffers... -            audioMixer().process(curBuf); +            mixer->process(curBuf);              // output audio to hardware              mLastWriteTime = systemTime();              mInWrite = true; -            mOutput->write(curBuf, mixBufferSize); +            size_t mixBufferSize = frameCount*channelCount*sizeof(int16_t); +            output->write(curBuf, mixBufferSize);              mNumWrites++;              mInWrite = false;              mStandby = false;              nsecs_t temp = systemTime();              standbyTime = temp + kStandbyTimeInNsecs;              nsecs_t delta = temp - mLastWriteTime; +            nsecs_t maxPeriod = seconds(frameCount) / sampleRate * 2;              if (delta > maxPeriod) {                  LOGW("write blocked for %llu msecs", ns2ms(delta));                  mNumDelayedWrites++; @@ -458,43 +544,60 @@ sp<IAudioTrack> AudioFlinger::createTrack(          uint32_t sampleRate,          int format,          int channelCount, -        int bufferCount, -        uint32_t flags) +        int frameCount, +        uint32_t flags, +        const sp<IMemory>& sharedBuffer, +        status_t *status)  { +    sp<Track> track; +    sp<TrackHandle> trackHandle; +    sp<Client> client; +    wp<Client> wclient; +    status_t lStatus; +      if (streamType >= AudioTrack::NUM_STREAM_TYPES) {          LOGE("invalid stream type"); -        return NULL; +        lStatus = BAD_VALUE; +        goto Exit;      } -    if (sampleRate > MAX_SAMPLE_RATE) { +    // Resampler implementation limits input sampling rate to 2 x output sampling rate. +    if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) {          LOGE("Sample rate out of range: %d", sampleRate); -        return NULL; +        lStatus = BAD_VALUE; +        goto Exit;      } -    sp<Track> track; -    sp<TrackHandle> trackHandle; -    Mutex::Autolock _l(mLock); +    { +        Mutex::Autolock _l(mLock); -    if (mSampleRate == 0) { -        LOGE("Audio driver not initialized."); -        return trackHandle; -    } +        if (mSampleRate == 0) { +            LOGE("Audio driver not initialized."); +            lStatus = NO_INIT; +            goto Exit; +        } -    sp<Client> client; -    wp<Client> wclient = mClients.valueFor(pid); +        wclient = mClients.valueFor(pid); -    if (wclient != NULL) { -        client = wclient.promote(); -    } else { -        client = new Client(this, pid); -        mClients.add(pid, client); +        if (wclient != NULL) { +            client = wclient.promote(); +        } else { +            client = new Client(this, pid); +            mClients.add(pid, client); +        } + +        track = new Track(this, client, streamType, sampleRate, format, +                channelCount, frameCount, sharedBuffer); +        mTracks.add(track); +        trackHandle = new TrackHandle(track); + +        lStatus = NO_ERROR;      } -    // FIXME: Buffer size should be based on sample rate for consistent latency -    track = new Track(this, client, streamType, sampleRate, format, -            channelCount, bufferCount, channelCount == 1 ? mMixBufferSize>>1 : mMixBufferSize); -    mTracks.add(track); -    trackHandle = new TrackHandle(track); +Exit: +    if(status) { +        *status = lStatus; +    }      return trackHandle;  } @@ -518,6 +621,16 @@ size_t AudioFlinger::frameCount() const      return mFrameCount;  } +uint32_t AudioFlinger::latency() const +{ +    if (mOutput) { +        return mOutput->latency(); +    } +    else { +        return 0; +    } +} +  status_t AudioFlinger::setMasterVolume(float value)  {      // check calling permissions @@ -549,6 +662,21 @@ status_t AudioFlinger::setRouting(int mode, uint32_t routes, uint32_t mask)          return BAD_VALUE;      } +#ifdef WITH_A2DP +    LOGD("setRouting %d %d %d\n", mode, routes, mask); +    if (mode == AudioSystem::MODE_NORMAL &&  +            (mask & AudioSystem::ROUTE_BLUETOOTH_A2DP)) { +        if (routes & AudioSystem::ROUTE_BLUETOOTH_A2DP) { +            LOGD("set output to A2DP\n"); +            setOutput(mA2dpOutput); +        } else { +            LOGD("set output to hardware audio\n"); +            setOutput(mHardwareOutput); +        } +        LOGD("setOutput done\n"); +    } +#endif +      AutoMutex lock(mHardwareLock);      mHardwareStatus = AUDIO_HW_GET_ROUTING;      uint32_t r; @@ -656,7 +784,7 @@ status_t AudioFlinger::setStreamVolume(int stream, float value)      if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {          return BAD_VALUE;      } -     +      mStreamTypes[stream].volume = value;      status_t ret = NO_ERROR;      if (stream == AudioTrack::VOICE_CALL) { @@ -750,6 +878,7 @@ status_t AudioFlinger::addTrack(const sp<Track>& track)          // buffers before playing. This is to ensure the client will          // effectively get the latency it requested.          track->mFillingUpStatus = Track::FS_FILLING; +        track->mResetDone = false;          mActiveTracks.add(track);          return NO_ERROR;      } @@ -771,7 +900,7 @@ void AudioFlinger::remove_track_l(wp<Track> track, int name)      if (t!=NULL) {          t->reset();      } -    audioMixer().deleteTrackName(name); +    audioMixer()->deleteTrackName(name);      mActiveTracks.remove(track);      mWaitWorkCV.broadcast();  } @@ -789,7 +918,7 @@ void AudioFlinger::destroyTrack(const sp<Track>& track)      if (mActiveTracks.indexOf(track) < 0) {          LOGV("remove track (%d) and delete from mixer", track->name());          mTracks.remove(track); -        audioMixer().deleteTrackName(keep->name()); +        audioMixer()->deleteTrackName(keep->name());      }  } @@ -823,38 +952,53 @@ AudioFlinger::TrackBase::TrackBase(              uint32_t sampleRate,              int format,              int channelCount, -            int bufferCount, -            int bufferSize) +            int frameCount, +            const sp<IMemory>& sharedBuffer)      :   RefBase(),          mAudioFlinger(audioFlinger),          mClient(client),          mStreamType(streamType), -        mFormat(format), -        mChannelCount(channelCount), -        mBufferCount(bufferCount), -        mFlags(0), -        mBufferSize(bufferSize), +        mFrameCount(0),          mState(IDLE), -        mClientTid(-1) +        mClientTid(-1), +        mFormat(format), +        mFlags(0)  { -    mName = audioFlinger->audioMixer().getTrackName(); +    mName = audioFlinger->audioMixer()->getTrackName();      if (mName < 0) {          LOGE("no more track names availlable");          return;      } +    LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size()); + +      // LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize); -    size_t size = sizeof(audio_track_cblk_t) + bufferCount * bufferSize; +   size_t size = sizeof(audio_track_cblk_t); +   size_t bufferSize = frameCount*channelCount*sizeof(int16_t); +   if (sharedBuffer == 0) { +       size += bufferSize; +   } +      mCblkMemory = client->heap()->allocate(size);      if (mCblkMemory != 0) {          mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer());          if (mCblk) { // construct the shared structure in-place.              new(mCblk) audio_track_cblk_t();              // clear all buffers -            mCblk->size = bufferSize; +            mCblk->frameCount = frameCount;              mCblk->sampleRate = sampleRate; -            mBuffers = (char*)mCblk + sizeof(audio_track_cblk_t); -            memset(mBuffers, 0, bufferCount * bufferSize); +            mCblk->channels = channelCount; +            if (sharedBuffer == 0) { +                mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t); +                memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t)); +                // Force underrun condition to avoid false underrun callback until first data is +                // written to buffer +                mCblk->flowControlFlag = 1; +            } else { +                mBuffer = sharedBuffer->pointer(); +            } +            mBufferEnd = (uint8_t *)mBuffer + bufferSize;          }      } else {          LOGE("not enough memory for AudioTrack size=%u", size); @@ -873,15 +1017,16 @@ AudioFlinger::TrackBase::~TrackBase()  void AudioFlinger::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)  {      buffer->raw = 0; -    buffer->frameCount = 0; +    mFrameCount = buffer->frameCount;      step(); +    buffer->frameCount = 0;  }  bool AudioFlinger::TrackBase::step() {      bool result;      audio_track_cblk_t* cblk = this->cblk(); -     -    result = cblk->stepServer(bufferCount());  + +    result = cblk->stepServer(mFrameCount);      if (!result) {          LOGV("stepServer failed acquiring cblk mutex");          mFlags |= STEPSERVER_FAILED; @@ -894,7 +1039,10 @@ void AudioFlinger::TrackBase::reset() {      cblk->user = 0;      cblk->server = 0; -    mFlags = 0;     +    cblk->userBase = 0; +    cblk->serverBase = 0; +    mFlags = 0; +    LOGV("TrackBase::reset");  }  sp<IMemory> AudioFlinger::TrackBase::getCblk() const @@ -906,6 +1054,27 @@ int AudioFlinger::TrackBase::sampleRate() const {      return mCblk->sampleRate;  } +int AudioFlinger::TrackBase::channelCount() const { +    return mCblk->channels; +} + +void* AudioFlinger::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const { +    audio_track_cblk_t* cblk = this->cblk(); +    int16_t *bufferStart = (int16_t *)mBuffer + (offset-cblk->serverBase)*cblk->channels; +    int16_t *bufferEnd = bufferStart + frames * cblk->channels; + +    // Check validity of returned pointer in case the track control block would have been corrupted. +    if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd) { +        LOGW("TrackBase::getBuffer buffer out of range:\n    start: %p, end %p , mBuffer %p mBufferEnd %p\n    \ +                server %d, serverBase %d, user %d, userBase %d", +                bufferStart, bufferEnd, mBuffer, mBufferEnd, +                cblk->server, cblk->serverBase, cblk->user, cblk->userBase); +        return 0; +    } + +    return bufferStart; +} +  // ----------------------------------------------------------------------------  AudioFlinger::Track::Track( @@ -915,13 +1084,14 @@ AudioFlinger::Track::Track(              uint32_t sampleRate,              int format,              int channelCount, -            int bufferCount, -            int bufferSize) -    :   TrackBase(audioFlinger, client, streamType, sampleRate, format, channelCount, bufferCount, bufferSize) +            int frameCount, +            const sp<IMemory>& sharedBuffer) +    :   TrackBase(audioFlinger, client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer)  {      mVolume[0] = 1.0f;      mVolume[1] = 1.0f;      mMute = false; +    mSharedBuffer = sharedBuffer;  }  AudioFlinger::Track::~Track() @@ -943,8 +1113,8 @@ void AudioFlinger::Track::dump(char* buffer, size_t size)              mClient->pid(),              mStreamType,              mFormat, -            mChannelCount, -            mBufferCount, +            mCblk->channels, +            mFrameCount,              mState,              mMute,              mFillingUpStatus, @@ -958,36 +1128,50 @@ void AudioFlinger::Track::dump(char* buffer, size_t size)  status_t AudioFlinger::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)  {       audio_track_cblk_t* cblk = this->cblk(); -     uint32_t u = cblk->user; -     uint32_t s = cblk->server; -      -     // Check if last stepServer failed, try to step now  +     uint32_t framesReady; +     uint32_t framesReq = buffer->frameCount; + +     // Check if last stepServer failed, try to step now       if (mFlags & TrackBase::STEPSERVER_FAILED) {           if (!step())  goto getNextBuffer_exit;           LOGV("stepServer recovered");           mFlags &= ~TrackBase::STEPSERVER_FAILED;       } -     if (LIKELY(u > s)) { -         int index = s & audio_track_cblk_t::BUFFER_MASK; -         buffer->raw = getBuffer(index); -         buffer->frameCount = mAudioFlinger->frameCount(); -         return NO_ERROR; +     framesReady = cblk->framesReady(); + +     if (LIKELY(framesReady)) { +        uint32_t s = cblk->server; +        uint32_t bufferEnd = cblk->serverBase + cblk->frameCount; + +        bufferEnd = (cblk->loopEnd < bufferEnd) ? cblk->loopEnd : bufferEnd; +        if (framesReq > framesReady) { +            framesReq = framesReady; +        } +        if (s + framesReq > bufferEnd) { +            framesReq = bufferEnd - s; +        } + +         buffer->raw = getBuffer(s, framesReq); +         if (buffer->raw == 0) goto getNextBuffer_exit; + +         buffer->frameCount = framesReq; +        return NO_ERROR;       } +  getNextBuffer_exit:       buffer->raw = 0;       buffer->frameCount = 0;       return NOT_ENOUGH_DATA;  } -bool AudioFlinger::Track::isReady(uint32_t u, int32_t s) const { +bool AudioFlinger::Track::isReady() const {      if (mFillingUpStatus != FS_FILLING) return true; -    const uint32_t u_seq = u & audio_track_cblk_t::SEQUENCE_MASK; -    const uint32_t u_buf = u & audio_track_cblk_t::BUFFER_MASK; -    const uint32_t s_seq = s & audio_track_cblk_t::SEQUENCE_MASK; -    const uint32_t s_buf = s & audio_track_cblk_t::BUFFER_MASK; -    if (u_seq > s_seq && u_buf == s_buf) { + +    if (mCblk->framesReady() >= mCblk->frameCount || +        mCblk->forceReady) {          mFillingUpStatus = FS_FILLED; +        mCblk->forceReady = 0;          return true;      }      return false; @@ -1006,7 +1190,7 @@ void AudioFlinger::Track::stop()      Mutex::Autolock _l(mAudioFlinger->mLock);      if (mState > STOPPED) {          mState = STOPPED; -        // If the track is not active (PAUSED and buffers full), flush buffers   +        // If the track is not active (PAUSED and buffers full), flush buffers          if (mAudioFlinger->mActiveTracks.indexOf(this) < 0) {              reset();          } @@ -1038,15 +1222,24 @@ void AudioFlinger::Track::flush()      // NOTE: reset() will reset cblk->user and cblk->server with      // the risk that at the same time, the AudioMixer is trying to read      // data. In this case, getNextBuffer() would return a NULL pointer -    // as audio buffer => the AudioMixer code MUST always test that pointer  -    // returned by getNextBuffer() is not NULL!  +    // as audio buffer => the AudioMixer code MUST always test that pointer +    // returned by getNextBuffer() is not NULL!      reset();  }  void AudioFlinger::Track::reset()  { -    TrackBase::reset(); -    mFillingUpStatus = FS_FILLING; +    // Do not reset twice to avoid discarding data written just after a flush and before +    // the audioflinger thread detects the track is stopped. +    if (!mResetDone) { +        TrackBase::reset(); +        // Force underrun condition to avoid false underrun callback until first data is +        // written to buffer +        mCblk->flowControlFlag = 1; +        mCblk->forceReady = 0; +        mFillingUpStatus = FS_FILLING;         +        mResetDone = true; +    }  }  void AudioFlinger::Track::mute(bool muted) @@ -1112,26 +1305,15 @@ status_t AudioFlinger::TrackHandle::onTransact(  // ---------------------------------------------------------------------------- -sp<AudioFlinger::AudioRecordThread> AudioFlinger::audioRecordThread() -{ -    Mutex::Autolock _l(mLock); -    return mAudioRecordThread; -} - -void AudioFlinger::endRecord() -{ -    Mutex::Autolock _l(mLock); -    mAudioRecordThread.clear(); -} -  sp<IAudioRecord> AudioFlinger::openRecord(          pid_t pid,          int streamType,          uint32_t sampleRate,          int format,          int channelCount, -        int bufferCount, -        uint32_t flags) +        int frameCount, +        uint32_t flags, +        status_t *status)  {      sp<AudioRecordThread> thread;      sp<RecordTrack> recordTrack; @@ -1139,46 +1321,46 @@ sp<IAudioRecord> AudioFlinger::openRecord(      sp<Client> client;      wp<Client> wclient;      AudioStreamIn* input = 0; +    int inFrameCount; +    size_t inputBufferSize; +    status_t lStatus;      // check calling permissions      if (!recordingAllowed()) { +        lStatus = PERMISSION_DENIED;          goto Exit;      }      if (uint32_t(streamType) >= AudioRecord::NUM_STREAM_TYPES) {          LOGE("invalid stream type"); +        lStatus = BAD_VALUE;          goto Exit;      }      if (sampleRate > MAX_SAMPLE_RATE) {          LOGE("Sample rate out of range"); +        lStatus = BAD_VALUE;          goto Exit;      }      if (mSampleRate == 0) {          LOGE("Audio driver not initialized"); +        lStatus = NO_INIT;          goto Exit;      } -    // Create audio thread - take mutex to prevent race condition -    { -        Mutex::Autolock _l(mLock); -        if (mAudioRecordThread != 0) { -            LOGE("Record channel already open"); -            goto Exit; -        } -        thread = new AudioRecordThread(this); -        mAudioRecordThread = thread; -    } -    // It's safe to release the mutex here since the client doesn't get a -    // handle until we return from this call - -    // open driver, initialize h/w -    input = mAudioHardware->openInputStream( -            AudioSystem::PCM_16_BIT, channelCount, sampleRate); -    if (!input) { -        LOGE("Error opening input stream"); -        mAudioRecordThread.clear(); +    if (mAudioRecordThread == 0) { +        LOGE("Audio record thread not started"); +        lStatus = NO_INIT; +        goto Exit; +    } + + +    // Check that audio input stream accepts requested audio parameters  +    inputBufferSize = mAudioHardware->getInputBufferSize(sampleRate, format, channelCount); +    if (inputBufferSize == 0) { +        lStatus = BAD_VALUE; +        LOGE("Bad audio input parameters: sampling rate %u, format %d, channels %d",  sampleRate, format, channelCount);          goto Exit;      } @@ -1194,37 +1376,38 @@ sp<IAudioRecord> AudioFlinger::openRecord(          }      } +    // frameCount must be a multiple of input buffer size +    inFrameCount = inputBufferSize/channelCount/sizeof(short); +    frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount; +      // create new record track and pass to record thread      recordTrack = new RecordTrack(this, client, streamType, sampleRate, -            format, channelCount, bufferCount, input->bufferSize()); - -    // spin up record thread -    thread->open(recordTrack, input); -    thread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO); +            format, channelCount, frameCount);      // return to handle to client      recordHandle = new RecordHandle(recordTrack); +    lStatus = NO_ERROR;  Exit: +    if (status) { +        *status = lStatus; +    }      return recordHandle;  } -status_t AudioFlinger::startRecord() { -    sp<AudioRecordThread> t = audioRecordThread(); -    if (t == 0) return NO_INIT; -    return t->start(); +status_t AudioFlinger::startRecord(RecordTrack* recordTrack) { +    if (mAudioRecordThread != 0) { +        return mAudioRecordThread->start(recordTrack);         +    } +    return NO_INIT;  } -void AudioFlinger::stopRecord() { -    sp<AudioRecordThread> t = audioRecordThread(); -    if (t != 0) t->stop(); +void AudioFlinger::stopRecord(RecordTrack* recordTrack) { +    if (mAudioRecordThread != 0) { +        mAudioRecordThread->stop(recordTrack); +    }  } -void AudioFlinger::exitRecord() -{ -    sp<AudioRecordThread> t = audioRecordThread(); -    if (t != 0) t->exit(); -}  // ---------------------------------------------------------------------------- @@ -1235,55 +1418,69 @@ AudioFlinger::RecordTrack::RecordTrack(              uint32_t sampleRate,              int format,              int channelCount, -            int bufferCount, -            int bufferSize) +            int frameCount)      :   TrackBase(audioFlinger, client, streamType, sampleRate, format, -            channelCount, bufferCount, bufferSize), +            channelCount, frameCount, 0),              mOverflow(false)  {  }  AudioFlinger::RecordTrack::~RecordTrack()  { -    mAudioFlinger->audioMixer().deleteTrackName(mName); -    mAudioFlinger->exitRecord(); +    mAudioFlinger->audioMixer()->deleteTrackName(mName);  }  status_t AudioFlinger::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)  { -     audio_track_cblk_t* cblk = this->cblk(); -     const uint32_t u_seq = cblk->user & audio_track_cblk_t::SEQUENCE_MASK; -     const uint32_t u_buf = cblk->user & audio_track_cblk_t::BUFFER_MASK; -     const uint32_t s_seq = cblk->server & audio_track_cblk_t::SEQUENCE_MASK; -     const uint32_t s_buf = cblk->server & audio_track_cblk_t::BUFFER_MASK; -      -     // Check if last stepServer failed, try to step now  -     if (mFlags & TrackBase::STEPSERVER_FAILED) { -         if (!step())  goto getNextBuffer_exit; -         LOGV("stepServer recovered"); -         mFlags &= ~TrackBase::STEPSERVER_FAILED; -     } +    audio_track_cblk_t* cblk = this->cblk(); +    uint32_t framesAvail; +    uint32_t framesReq = buffer->frameCount; + +     // Check if last stepServer failed, try to step now +    if (mFlags & TrackBase::STEPSERVER_FAILED) { +        if (!step()) goto getNextBuffer_exit; +        LOGV("stepServer recovered"); +        mFlags &= ~TrackBase::STEPSERVER_FAILED; +    } -     if (LIKELY(s_seq == u_seq || s_buf != u_buf)) { -         buffer->raw = getBuffer(s_buf); -         buffer->frameCount = mAudioFlinger->frameCount(); -         return NO_ERROR; -     } +    framesAvail = cblk->framesAvailable_l(); -getNextBuffer_exit:      -     buffer->raw = 0; -     buffer->frameCount = 0; -     return NOT_ENOUGH_DATA; +    if (LIKELY(framesAvail)) { +        uint32_t s = cblk->server; +        uint32_t bufferEnd = cblk->serverBase + cblk->frameCount; + +        if (framesReq > framesAvail) { +            framesReq = framesAvail; +        } +        if (s + framesReq > bufferEnd) { +            framesReq = bufferEnd - s; +        } + +        buffer->raw = getBuffer(s, framesReq); +        if (buffer->raw == 0) goto getNextBuffer_exit; + +        buffer->frameCount = framesReq; +        return NO_ERROR; +    } + +getNextBuffer_exit: +    buffer->raw = 0; +    buffer->frameCount = 0; +    return NOT_ENOUGH_DATA;  }  status_t AudioFlinger::RecordTrack::start()  { -    return mAudioFlinger->startRecord(); +    return mAudioFlinger->startRecord(this);  }  void AudioFlinger::RecordTrack::stop()  { -    mAudioFlinger->stopRecord(); +    mAudioFlinger->stopRecord(this); +    TrackBase::reset(); +    // Force overerrun condition to avoid false overrun callback until first data is +    // read from buffer +    mCblk->flowControlFlag = 1;  }  // ---------------------------------------------------------------------------- @@ -1294,7 +1491,9 @@ AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::RecordTrack>& re  {  } -AudioFlinger::RecordHandle::~RecordHandle() {} +AudioFlinger::RecordHandle::~RecordHandle() { +    stop(); +}  status_t AudioFlinger::RecordHandle::start() {      LOGV("RecordHandle::start()"); @@ -1318,10 +1517,8 @@ status_t AudioFlinger::RecordHandle::onTransact(  // ---------------------------------------------------------------------------- -AudioFlinger::AudioRecordThread::AudioRecordThread(const sp<AudioFlinger>& audioFlinger) : -    mAudioFlinger(audioFlinger), -    mRecordTrack(0), -    mInput(0), +AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware) : +    mAudioHardware(audioHardware),      mActive(false)  {  } @@ -1333,108 +1530,123 @@ AudioFlinger::AudioRecordThread::~AudioRecordThread()  bool AudioFlinger::AudioRecordThread::threadLoop()  {      LOGV("AudioRecordThread: start record loop"); +    AudioBufferProvider::Buffer buffer; +    int inBufferSize = 0; +    int inFrameCount = 0; +    AudioStreamIn* input = 0; +    mActive = 0; +          // start recording      while (!exitPending()) {          if (!mActive) {              mLock.lock();              if (!mActive && !exitPending()) {                  LOGV("AudioRecordThread: loop stopping"); +                if (input) { +                    delete input; +                    input = 0; +                } +                mRecordTrack.clear(); +                  mWaitWorkCV.wait(mLock); +                                 LOGV("AudioRecordThread: loop starting"); +                if (mRecordTrack != 0) { +                    input = mAudioHardware->openInputStream(mRecordTrack->format(),  +                                            mRecordTrack->channelCount(),  +                                            mRecordTrack->sampleRate(),  +                                            &mStartStatus); +                    if (input != 0) { +                        inBufferSize = input->bufferSize(); +                        inFrameCount = inBufferSize/input->frameSize();                         +                    } +                } else { +                    mStartStatus = NO_INIT; +                } +                if (mStartStatus !=NO_ERROR) { +                    LOGW("record start failed, status %d", mStartStatus); +                    mActive = false; +                    mRecordTrack.clear();                     +                } +                mWaitWorkCV.signal();              }              mLock.unlock(); -        } else { -            // promote strong ref so track isn't deleted while we access it -            sp<RecordTrack> t = mRecordTrack.promote(); +        } else if (mRecordTrack != 0){ -            // if we lose the weak reference, client is gone. -            if (t == 0) { -                LOGV("AudioRecordThread: client deleted track"); -                break; -            } - -            if (LIKELY(t->getNextBuffer(&mBuffer) == NO_ERROR)) { -                if (mInput->read(mBuffer.raw, t->mBufferSize) < 0) { +            buffer.frameCount = inFrameCount; +            if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR)) { +                LOGV("AudioRecordThread read: %d frames", buffer.frameCount); +                if (input->read(buffer.raw, inBufferSize) < 0) {                      LOGE("Error reading audio input");                      sleep(1);                  } -                t->releaseBuffer(&mBuffer); +                mRecordTrack->releaseBuffer(&buffer); +                mRecordTrack->overflow();              }              // client isn't retrieving buffers fast enough              else { -                if (!t->setOverflow()) +                if (!mRecordTrack->setOverflow())                      LOGW("AudioRecordThread: buffer overflow"); +                // Release the processor for a while before asking for a new buffer. +                // This will give the application more chance to read from the buffer and +                // clear the overflow. +                usleep(5000);              }          } -    }; - -    // close hardware -    close(); +    } -    // delete this object - no more data references after this call -    mAudioFlinger->endRecord(); -    return false; -} -status_t AudioFlinger::AudioRecordThread::open(const sp<RecordTrack>& recordTrack, AudioStreamIn *input) { -    LOGV("AudioRecordThread::open"); -    // check for record channel already open -    AutoMutex lock(&mLock); -    if (mRecordTrack != NULL) { -        LOGE("Record channel already open"); -        return ALREADY_EXISTS; +    if (input) { +        delete input;      } -    mRecordTrack = recordTrack; -    mInput = input; -    return NO_ERROR; +    mRecordTrack.clear(); +     +    return false;  } -status_t AudioFlinger::AudioRecordThread::start() +status_t AudioFlinger::AudioRecordThread::start(RecordTrack* recordTrack)  {      LOGV("AudioRecordThread::start");      AutoMutex lock(&mLock); -    if (mActive) return -EBUSY; +    mActive = true; +    // If starting the active track, just reset mActive in case a stop +    // was pending and exit +    if (recordTrack == mRecordTrack.get()) return NO_ERROR; + +    if (mRecordTrack != 0) return -EBUSY; -    sp<RecordTrack> t = mRecordTrack.promote(); -    if (t == 0) return UNKNOWN_ERROR; +    mRecordTrack = recordTrack;      // signal thread to start      LOGV("Signal record thread"); -    mActive = true;      mWaitWorkCV.signal(); -    return NO_ERROR; +    mWaitWorkCV.wait(mLock); +    LOGV("Record started, status %d", mStartStatus); +    return mStartStatus;  } -void AudioFlinger::AudioRecordThread::stop() { +void AudioFlinger::AudioRecordThread::stop(RecordTrack* recordTrack) {      LOGV("AudioRecordThread::stop");      AutoMutex lock(&mLock); -    if (mActive) { +    if (mActive && (recordTrack == mRecordTrack.get())) {          mActive = false; -        mWaitWorkCV.signal();      }  }  void AudioFlinger::AudioRecordThread::exit()  {      LOGV("AudioRecordThread::exit"); -    AutoMutex lock(&mLock); -    requestExit(); -    mWaitWorkCV.signal(); +    { +        AutoMutex lock(&mLock); +        requestExit(); +        mWaitWorkCV.signal(); +    } +    requestExitAndWait();  } -status_t AudioFlinger::AudioRecordThread::close() -{ -    LOGV("AudioRecordThread::close"); -    AutoMutex lock(&mLock); -    if (!mInput) return NO_INIT; -    delete mInput; -    mInput = 0; -    return NO_ERROR; -} -  status_t AudioFlinger::onTransact(          uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)  { |