diff options
Diffstat (limited to 'services/audioflinger/Tracks.cpp')
-rw-r--r-- | services/audioflinger/Tracks.cpp | 136 |
1 files changed, 101 insertions, 35 deletions
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index fccc7b8..92ed46a 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -116,12 +116,11 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase( if (client != 0) { mCblkMemory = client->heap()->allocate(size); - if (mCblkMemory != 0) { - mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer()); - // can't assume mCblk != NULL - } else { + if (mCblkMemory == 0 || + (mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer())) == NULL) { ALOGE("not enough memory for AudioTrack size=%u", size); client->heap()->dump("AudioTrack"); + mCblkMemory.clear(); return; } } else { @@ -134,7 +133,6 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase( if (mCblk != NULL) { new(mCblk) audio_track_cblk_t(); // clear all buffers - mCblk->frameCount_ = frameCount; if (sharedBuffer == 0) { mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t); memset(mBuffer, 0, bufferSize); @@ -148,7 +146,7 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase( #ifdef TEE_SINK if (mTeeSinkTrackEnabled) { NBAIO_Format pipeFormat = Format_from_SR_C(mSampleRate, mChannelCount); - if (pipeFormat != Format_Invalid) { + if (Format_isValid(pipeFormat)) { Pipe *pipe = new Pipe(mTeeSinkTrackFrames, pipeFormat); size_t numCounterOffers = 0; const NBAIO_Format offers[1] = {pipeFormat}; @@ -275,6 +273,11 @@ status_t AudioFlinger::TrackHandle::queueTimedBuffer(const sp<IMemory>& buffer, if (!mTrack->isTimedTrack()) return INVALID_OPERATION; + if (buffer == 0 || buffer->pointer() == NULL) { + ALOGE("queueTimedBuffer() buffer is 0 or has NULL pointer()"); + return BAD_VALUE; + } + PlaybackThread::TimedTrack* tt = reinterpret_cast<PlaybackThread::TimedTrack*>(mTrack.get()); return tt->queueTimedBuffer(buffer, pts); @@ -344,7 +347,8 @@ AudioFlinger::PlaybackThread::Track::Track( mCachedVolume(1.0), mIsInvalid(false), mAudioTrackServerProxy(NULL), - mResumeToStopping(false) + mResumeToStopping(false), + mFlushHwPending(false) { if (mCblk != NULL) { if (sharedBuffer == 0) { @@ -396,6 +400,15 @@ AudioFlinger::PlaybackThread::Track::~Track() } } +status_t AudioFlinger::PlaybackThread::Track::initCheck() const +{ + status_t status = TrackBase::initCheck(); + if (status == NO_ERROR && mName < 0) { + status = NO_MEMORY; + } + return status; +} + void AudioFlinger::PlaybackThread::Track::destroy() { // NOTE: destroyTrack_l() can remove a strong reference to this Track @@ -422,17 +435,19 @@ void AudioFlinger::PlaybackThread::Track::destroy() /*static*/ void AudioFlinger::PlaybackThread::Track::appendDumpHeader(String8& result) { - result.append(" Name Client Type Fmt Chn mask Session fCount S F SRate " + result.append(" Name Active Client Type Fmt Chn mask Session fCount S F SRate " "L dB R dB Server Main buf Aux Buf Flags UndFrmCnt\n"); } -void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size) +void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size, bool active) { uint32_t vlr = mAudioTrackServerProxy->getVolumeLR(); if (isFastTrack()) { - sprintf(buffer, " F %2d", mFastIndex); + sprintf(buffer, " F %2d", mFastIndex); + } else if (mName >= AudioMixer::TRACK0) { + sprintf(buffer, " %4d", mName - AudioMixer::TRACK0); } else { - sprintf(buffer, " %4d", mName - AudioMixer::TRACK0); + sprintf(buffer, " none"); } track_state state = mState; char stateChar; @@ -487,8 +502,9 @@ void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size) nowInUnderrun = '?'; break; } - snprintf(&buffer[7], size-7, " %6u %4u %08X %08X %7u %6zu %1c %1d %5u %5.2g %5.2g " + snprintf(&buffer[8], size-8, " %6s %6u %4u %08X %08X %7u %6zu %1c %1d %5u %5.2g %5.2g " "%08X %p %p 0x%03X %9u%c\n", + active ? "yes" : "no", (mClient == 0) ? getpid_cached : mClient->pid(), mStreamType, mFormat, @@ -514,7 +530,7 @@ uint32_t AudioFlinger::PlaybackThread::Track::sampleRate() const { // AudioBufferProvider interface status_t AudioFlinger::PlaybackThread::Track::getNextBuffer( - AudioBufferProvider::Buffer* buffer, int64_t pts) + AudioBufferProvider::Buffer* buffer, int64_t pts __unused) { ServerProxy::Buffer buf; size_t desiredFrames = buffer->frameCount; @@ -551,7 +567,7 @@ size_t AudioFlinger::PlaybackThread::Track::framesReleased() const // Don't call for fast tracks; the framesReady() could result in priority inversion bool AudioFlinger::PlaybackThread::Track::isReady() const { - if (mFillingUpStatus != FS_FILLING || isStopped() || isPausing()) { + if (mFillingUpStatus != FS_FILLING || isStopped() || isPausing() || isStopping()) { return true; } @@ -564,8 +580,8 @@ bool AudioFlinger::PlaybackThread::Track::isReady() const { return false; } -status_t AudioFlinger::PlaybackThread::Track::start(AudioSystem::sync_event_t event, - int triggerSession) +status_t AudioFlinger::PlaybackThread::Track::start(AudioSystem::sync_event_t event __unused, + int triggerSession __unused) { status_t status = NO_ERROR; ALOGV("start(%d), calling pid %d session %d", @@ -719,6 +735,7 @@ void AudioFlinger::PlaybackThread::Track::flush() mRetryCount = PlaybackThread::kMaxTrackRetriesOffload; } + mFlushHwPending = true; mResumeToStopping = false; } else { if (mState != STOPPING_1 && mState != STOPPING_2 && mState != STOPPED && @@ -739,11 +756,19 @@ void AudioFlinger::PlaybackThread::Track::flush() // Prevent flush being lost if the track is flushed and then resumed // before mixer thread can run. This is important when offloading // because the hardware buffer could hold a large amount of audio - playbackThread->flushOutput_l(); playbackThread->broadcast_l(); } } +// must be called with thread lock held +void AudioFlinger::PlaybackThread::Track::flushAck() +{ + if (!isOffloaded()) + return; + + mFlushHwPending = false; +} + void AudioFlinger::PlaybackThread::Track::reset() { // Do not reset twice to avoid discarding data written just after a flush and before @@ -979,7 +1004,8 @@ AudioFlinger::PlaybackThread::TimedTrack::create( size_t frameCount, const sp<IMemory>& sharedBuffer, int sessionId, - int uid) { + int uid) +{ if (!client->reserveTimedTrack()) return 0; @@ -1045,15 +1071,14 @@ status_t AudioFlinger::PlaybackThread::TimedTrack::allocateTimedBuffer( mTimedMemoryDealer = new MemoryDealer(kTimedBufferHeapSize, "AudioFlingerTimed"); - if (mTimedMemoryDealer == NULL) + if (mTimedMemoryDealer == NULL) { return NO_MEMORY; + } } sp<IMemory> newBuffer = mTimedMemoryDealer->allocate(size); - if (newBuffer == NULL) { - newBuffer = mTimedMemoryDealer->allocate(size); - if (newBuffer == NULL) - return NO_MEMORY; + if (newBuffer == 0 || newBuffer->pointer() == NULL) { + return NO_MEMORY; } *buffer = newBuffer; @@ -1152,7 +1177,7 @@ void AudioFlinger::PlaybackThread::TimedTrack::trimTimedBufferQueueHead_l( void AudioFlinger::PlaybackThread::TimedTrack::updateFramesPendingAfterTrim_l( const TimedBuffer& buf, - const char* logTag) { + const char* logTag __unused) { uint32_t bufBytes = buf.buffer()->size(); uint32_t consumedAlready = buf.position(); @@ -1504,9 +1529,9 @@ AudioFlinger::PlaybackThread::OutputTrack::OutputTrack( mOutBuffer.frameCount = 0; playbackThread->mTracks.add(this); ALOGV("OutputTrack constructor mCblk %p, mBuffer %p, " - "mCblk->frameCount_ %u, mChannelMask 0x%08x", + "frameCount %u, mChannelMask 0x%08x", mCblk, mBuffer, - mCblk->frameCount_, mChannelMask); + frameCount, mChannelMask); // since client and server are in the same process, // the buffer has the same virtual address on both sides mClientProxy = new AudioTrackClientProxy(mCblk, mBuffer, mFrameCount, mFrameSize); @@ -1760,24 +1785,39 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack( int uid) : TrackBase(thread, client, sampleRate, format, channelMask, frameCount, 0 /*sharedBuffer*/, sessionId, uid, false /*isOut*/), - mOverflow(false) + mOverflow(false), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpOutFrameCount(0), + // See real initialization of mRsmpInFront at RecordThread::start() + mRsmpInUnrel(0), mRsmpInFront(0), mFramesToDrop(0), mResamplerBufferProvider(NULL) { ALOGV("RecordTrack constructor"); if (mCblk != NULL) { - mAudioRecordServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount, - mFrameSize); - mServerProxy = mAudioRecordServerProxy; + mServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount, mFrameSize); + } + + uint32_t channelCount = popcount(channelMask); + // FIXME I don't understand either of the channel count checks + if (thread->mSampleRate != sampleRate && thread->mChannelCount <= FCC_2 && + channelCount <= FCC_2) { + // sink SR + mResampler = AudioResampler::create(16, thread->mChannelCount, sampleRate); + // source SR + mResampler->setSampleRate(thread->mSampleRate); + mResampler->setVolume(AudioMixer::UNITY_GAIN, AudioMixer::UNITY_GAIN); + mResamplerBufferProvider = new ResamplerBufferProvider(this); } } AudioFlinger::RecordThread::RecordTrack::~RecordTrack() { ALOGV("%s", __func__); + delete mResampler; + delete[] mRsmpOutBuffer; + delete mResamplerBufferProvider; } // AudioBufferProvider interface status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer, - int64_t pts) + int64_t pts __unused) { ServerProxy::Buffer buf; buf.mFrameCount = buffer->frameCount; @@ -1845,19 +1885,45 @@ void AudioFlinger::RecordThread::RecordTrack::invalidate() /*static*/ void AudioFlinger::RecordThread::RecordTrack::appendDumpHeader(String8& result) { - result.append("Client Fmt Chn mask Session S Server fCount\n"); + result.append(" Active Client Fmt Chn mask Session S Server fCount Resampling\n"); } -void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size) +void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size, bool active) { - snprintf(buffer, size, "%6u %3u %08X %7u %1d %08X %6zu\n", + snprintf(buffer, size, " %6s %6u %3u %08X %7u %1d %08X %6zu %10d\n", + active ? "yes" : "no", (mClient == 0) ? getpid_cached : mClient->pid(), mFormat, mChannelMask, mSessionId, mState, mCblk->mServer, - mFrameCount); + mFrameCount, + mResampler != NULL); + +} + +void AudioFlinger::RecordThread::RecordTrack::handleSyncStartEvent(const sp<SyncEvent>& event) +{ + if (event == mSyncStartEvent) { + ssize_t framesToDrop = 0; + sp<ThreadBase> threadBase = mThread.promote(); + if (threadBase != 0) { + // TODO: use actual buffer filling status instead of 2 buffers when info is available + // from audio HAL + framesToDrop = threadBase->mFrameCount * 2; + } + mFramesToDrop = framesToDrop; + } +} + +void AudioFlinger::RecordThread::RecordTrack::clearSyncStartEvent() +{ + if (mSyncStartEvent != 0) { + mSyncStartEvent->cancel(); + mSyncStartEvent.clear(); + } + mFramesToDrop = 0; } }; // namespace android |