| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 1 | /* | 
 | 2 | ** | 
 | 3 | ** Copyright 2012, The Android Open Source Project | 
 | 4 | ** | 
 | 5 | ** Licensed under the Apache License, Version 2.0 (the "License"); | 
 | 6 | ** you may not use this file except in compliance with the License. | 
 | 7 | ** You may obtain a copy of the License at | 
 | 8 | ** | 
 | 9 | **     http://www.apache.org/licenses/LICENSE-2.0 | 
 | 10 | ** | 
 | 11 | ** Unless required by applicable law or agreed to in writing, software | 
 | 12 | ** distributed under the License is distributed on an "AS IS" BASIS, | 
 | 13 | ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | 14 | ** See the License for the specific language governing permissions and | 
 | 15 | ** limitations under the License. | 
 | 16 | */ | 
 | 17 |  | 
 | 18 |  | 
 | 19 | #define LOG_TAG "AudioFlinger" | 
 | 20 | //#define LOG_NDEBUG 0 | 
 | 21 |  | 
 | 22 | #include <math.h> | 
 | 23 | #include <cutils/compiler.h> | 
 | 24 | #include <utils/Log.h> | 
 | 25 |  | 
 | 26 | #include <private/media/AudioTrackShared.h> | 
 | 27 |  | 
 | 28 | #include <common_time/cc_helper.h> | 
 | 29 | #include <common_time/local_clock.h> | 
 | 30 |  | 
 | 31 | #include "AudioMixer.h" | 
 | 32 | #include "AudioFlinger.h" | 
 | 33 | #include "ServiceUtilities.h" | 
 | 34 |  | 
 | 35 | // ---------------------------------------------------------------------------- | 
 | 36 |  | 
 | 37 | // Note: the following macro is used for extremely verbose logging message.  In | 
 | 38 | // order to run with ALOG_ASSERT turned on, we need to have LOG_NDEBUG set to | 
 | 39 | // 0; but one side effect of this is to turn all LOGV's as well.  Some messages | 
 | 40 | // are so verbose that we want to suppress them even when we have ALOG_ASSERT | 
 | 41 | // turned on.  Do not uncomment the #def below unless you really know what you | 
 | 42 | // are doing and want to see all of the extremely verbose messages. | 
 | 43 | //#define VERY_VERY_VERBOSE_LOGGING | 
 | 44 | #ifdef VERY_VERY_VERBOSE_LOGGING | 
 | 45 | #define ALOGVV ALOGV | 
 | 46 | #else | 
 | 47 | #define ALOGVV(a...) do { } while(0) | 
 | 48 | #endif | 
 | 49 |  | 
 | 50 | namespace android { | 
 | 51 |  | 
 | 52 | // ---------------------------------------------------------------------------- | 
 | 53 | //      TrackBase | 
 | 54 | // ---------------------------------------------------------------------------- | 
 | 55 |  | 
 | 56 | // TrackBase constructor must be called with AudioFlinger::mLock held | 
 | 57 | AudioFlinger::ThreadBase::TrackBase::TrackBase( | 
 | 58 |             ThreadBase *thread, | 
 | 59 |             const sp<Client>& client, | 
 | 60 |             uint32_t sampleRate, | 
 | 61 |             audio_format_t format, | 
 | 62 |             audio_channel_mask_t channelMask, | 
 | 63 |             size_t frameCount, | 
 | 64 |             const sp<IMemory>& sharedBuffer, | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 65 |             int sessionId, | 
 | 66 |             bool isOut) | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 67 |     :   RefBase(), | 
 | 68 |         mThread(thread), | 
 | 69 |         mClient(client), | 
 | 70 |         mCblk(NULL), | 
 | 71 |         // mBuffer | 
 | 72 |         // mBufferEnd | 
 | 73 |         mStepCount(0), | 
 | 74 |         mState(IDLE), | 
 | 75 |         mSampleRate(sampleRate), | 
 | 76 |         mFormat(format), | 
 | 77 |         mChannelMask(channelMask), | 
 | 78 |         mChannelCount(popcount(channelMask)), | 
 | 79 |         mFrameSize(audio_is_linear_pcm(format) ? | 
 | 80 |                 mChannelCount * audio_bytes_per_sample(format) : sizeof(int8_t)), | 
 | 81 |         mFrameCount(frameCount), | 
 | 82 |         mStepServerFailed(false), | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 83 |         mSessionId(sessionId), | 
 | 84 |         mIsOut(isOut), | 
 | 85 |         mServerProxy(NULL) | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 86 | { | 
 | 87 |     // client == 0 implies sharedBuffer == 0 | 
 | 88 |     ALOG_ASSERT(!(client == 0 && sharedBuffer != 0)); | 
 | 89 |  | 
 | 90 |     ALOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), | 
 | 91 |             sharedBuffer->size()); | 
 | 92 |  | 
 | 93 |     // ALOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize); | 
 | 94 |     size_t size = sizeof(audio_track_cblk_t); | 
 | 95 |     size_t bufferSize = frameCount * mFrameSize; | 
 | 96 |     if (sharedBuffer == 0) { | 
 | 97 |         size += bufferSize; | 
 | 98 |     } | 
 | 99 |  | 
 | 100 |     if (client != 0) { | 
 | 101 |         mCblkMemory = client->heap()->allocate(size); | 
 | 102 |         if (mCblkMemory != 0) { | 
 | 103 |             mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer()); | 
 | 104 |             // can't assume mCblk != NULL | 
 | 105 |         } else { | 
 | 106 |             ALOGE("not enough memory for AudioTrack size=%u", size); | 
 | 107 |             client->heap()->dump("AudioTrack"); | 
 | 108 |             return; | 
 | 109 |         } | 
 | 110 |     } else { | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 111 |         // this syntax avoids calling the audio_track_cblk_t constructor twice | 
 | 112 |         mCblk = (audio_track_cblk_t *) new uint8_t[size]; | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 113 |         // assume mCblk != NULL | 
 | 114 |     } | 
 | 115 |  | 
 | 116 |     // construct the shared structure in-place. | 
 | 117 |     if (mCblk != NULL) { | 
 | 118 |         new(mCblk) audio_track_cblk_t(); | 
 | 119 |         // clear all buffers | 
 | 120 |         mCblk->frameCount_ = frameCount; | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 121 | // uncomment the following lines to quickly test 32-bit wraparound | 
 | 122 | //      mCblk->user = 0xffff0000; | 
 | 123 | //      mCblk->server = 0xffff0000; | 
 | 124 | //      mCblk->userBase = 0xffff0000; | 
 | 125 | //      mCblk->serverBase = 0xffff0000; | 
 | 126 |         if (sharedBuffer == 0) { | 
 | 127 |             mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t); | 
 | 128 |             memset(mBuffer, 0, bufferSize); | 
 | 129 |             // Force underrun condition to avoid false underrun callback until first data is | 
 | 130 |             // written to buffer (other flags are cleared) | 
 | 131 |             mCblk->flags = CBLK_UNDERRUN; | 
 | 132 |         } else { | 
 | 133 |             mBuffer = sharedBuffer->pointer(); | 
 | 134 |         } | 
 | 135 |         mBufferEnd = (uint8_t *)mBuffer + bufferSize; | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 136 |         mServerProxy = new ServerProxy(mCblk, mBuffer, frameCount, mFrameSize, isOut); | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 137 |     } | 
 | 138 | } | 
 | 139 |  | 
 | 140 | AudioFlinger::ThreadBase::TrackBase::~TrackBase() | 
 | 141 | { | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 142 |     // delete the proxy before deleting the shared memory it refers to, to avoid dangling reference | 
 | 143 |     delete mServerProxy; | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 144 |     if (mCblk != NULL) { | 
 | 145 |         if (mClient == 0) { | 
 | 146 |             delete mCblk; | 
 | 147 |         } else { | 
 | 148 |             mCblk->~audio_track_cblk_t();   // destroy our shared-structure. | 
 | 149 |         } | 
 | 150 |     } | 
 | 151 |     mCblkMemory.clear();    // free the shared memory before releasing the heap it belongs to | 
 | 152 |     if (mClient != 0) { | 
 | 153 |         // Client destructor must run with AudioFlinger mutex locked | 
 | 154 |         Mutex::Autolock _l(mClient->audioFlinger()->mLock); | 
 | 155 |         // If the client's reference count drops to zero, the associated destructor | 
 | 156 |         // must run with AudioFlinger lock held. Thus the explicit clear() rather than | 
 | 157 |         // relying on the automatic clear() at end of scope. | 
 | 158 |         mClient.clear(); | 
 | 159 |     } | 
 | 160 | } | 
 | 161 |  | 
 | 162 | // AudioBufferProvider interface | 
 | 163 | // getNextBuffer() = 0; | 
 | 164 | // This implementation of releaseBuffer() is used by Track and RecordTrack, but not TimedTrack | 
 | 165 | void AudioFlinger::ThreadBase::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer) | 
 | 166 | { | 
 | 167 |     buffer->raw = NULL; | 
 | 168 |     mStepCount = buffer->frameCount; | 
 | 169 |     // FIXME See note at getNextBuffer() | 
 | 170 |     (void) step();      // ignore return value of step() | 
 | 171 |     buffer->frameCount = 0; | 
 | 172 | } | 
 | 173 |  | 
 | 174 | bool AudioFlinger::ThreadBase::TrackBase::step() { | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 175 |     bool result = mServerProxy->step(mStepCount); | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 176 |     if (!result) { | 
 | 177 |         ALOGV("stepServer failed acquiring cblk mutex"); | 
 | 178 |         mStepServerFailed = true; | 
 | 179 |     } | 
 | 180 |     return result; | 
 | 181 | } | 
 | 182 |  | 
 | 183 | void AudioFlinger::ThreadBase::TrackBase::reset() { | 
 | 184 |     audio_track_cblk_t* cblk = this->cblk(); | 
 | 185 |  | 
 | 186 |     cblk->user = 0; | 
 | 187 |     cblk->server = 0; | 
 | 188 |     cblk->userBase = 0; | 
 | 189 |     cblk->serverBase = 0; | 
 | 190 |     mStepServerFailed = false; | 
 | 191 |     ALOGV("TrackBase::reset"); | 
 | 192 | } | 
 | 193 |  | 
 | 194 | uint32_t AudioFlinger::ThreadBase::TrackBase::sampleRate() const { | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 195 |     return mServerProxy->getSampleRate(); | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 196 | } | 
 | 197 |  | 
 | 198 | void* AudioFlinger::ThreadBase::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const { | 
 | 199 |     audio_track_cblk_t* cblk = this->cblk(); | 
 | 200 |     int8_t *bufferStart = (int8_t *)mBuffer + (offset-cblk->serverBase) * mFrameSize; | 
 | 201 |     int8_t *bufferEnd = bufferStart + frames * mFrameSize; | 
 | 202 |  | 
 | 203 |     // Check validity of returned pointer in case the track control block would have been corrupted. | 
 | 204 |     ALOG_ASSERT(!(bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd), | 
 | 205 |             "TrackBase::getBuffer buffer out of range:\n" | 
 | 206 |                 "    start: %p, end %p , mBuffer %p mBufferEnd %p\n" | 
 | 207 |                 "    server %u, serverBase %u, user %u, userBase %u, frameSize %u", | 
 | 208 |                 bufferStart, bufferEnd, mBuffer, mBufferEnd, | 
 | 209 |                 cblk->server, cblk->serverBase, cblk->user, cblk->userBase, mFrameSize); | 
 | 210 |  | 
 | 211 |     return bufferStart; | 
 | 212 | } | 
 | 213 |  | 
 | 214 | status_t AudioFlinger::ThreadBase::TrackBase::setSyncEvent(const sp<SyncEvent>& event) | 
 | 215 | { | 
 | 216 |     mSyncEvents.add(event); | 
 | 217 |     return NO_ERROR; | 
 | 218 | } | 
 | 219 |  | 
 | 220 | // ---------------------------------------------------------------------------- | 
 | 221 | //      Playback | 
 | 222 | // ---------------------------------------------------------------------------- | 
 | 223 |  | 
 | 224 | AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::PlaybackThread::Track>& track) | 
 | 225 |     : BnAudioTrack(), | 
 | 226 |       mTrack(track) | 
 | 227 | { | 
 | 228 | } | 
 | 229 |  | 
 | 230 | AudioFlinger::TrackHandle::~TrackHandle() { | 
 | 231 |     // just stop the track on deletion, associated resources | 
 | 232 |     // will be freed from the main thread once all pending buffers have | 
 | 233 |     // been played. Unless it's not in the active track list, in which | 
 | 234 |     // case we free everything now... | 
 | 235 |     mTrack->destroy(); | 
 | 236 | } | 
 | 237 |  | 
 | 238 | sp<IMemory> AudioFlinger::TrackHandle::getCblk() const { | 
 | 239 |     return mTrack->getCblk(); | 
 | 240 | } | 
 | 241 |  | 
 | 242 | status_t AudioFlinger::TrackHandle::start() { | 
 | 243 |     return mTrack->start(); | 
 | 244 | } | 
 | 245 |  | 
 | 246 | void AudioFlinger::TrackHandle::stop() { | 
 | 247 |     mTrack->stop(); | 
 | 248 | } | 
 | 249 |  | 
 | 250 | void AudioFlinger::TrackHandle::flush() { | 
 | 251 |     mTrack->flush(); | 
 | 252 | } | 
 | 253 |  | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 254 | void AudioFlinger::TrackHandle::pause() { | 
 | 255 |     mTrack->pause(); | 
 | 256 | } | 
 | 257 |  | 
 | 258 | status_t AudioFlinger::TrackHandle::attachAuxEffect(int EffectId) | 
 | 259 | { | 
 | 260 |     return mTrack->attachAuxEffect(EffectId); | 
 | 261 | } | 
 | 262 |  | 
 | 263 | status_t AudioFlinger::TrackHandle::allocateTimedBuffer(size_t size, | 
 | 264 |                                                          sp<IMemory>* buffer) { | 
 | 265 |     if (!mTrack->isTimedTrack()) | 
 | 266 |         return INVALID_OPERATION; | 
 | 267 |  | 
 | 268 |     PlaybackThread::TimedTrack* tt = | 
 | 269 |             reinterpret_cast<PlaybackThread::TimedTrack*>(mTrack.get()); | 
 | 270 |     return tt->allocateTimedBuffer(size, buffer); | 
 | 271 | } | 
 | 272 |  | 
 | 273 | status_t AudioFlinger::TrackHandle::queueTimedBuffer(const sp<IMemory>& buffer, | 
 | 274 |                                                      int64_t pts) { | 
 | 275 |     if (!mTrack->isTimedTrack()) | 
 | 276 |         return INVALID_OPERATION; | 
 | 277 |  | 
 | 278 |     PlaybackThread::TimedTrack* tt = | 
 | 279 |             reinterpret_cast<PlaybackThread::TimedTrack*>(mTrack.get()); | 
 | 280 |     return tt->queueTimedBuffer(buffer, pts); | 
 | 281 | } | 
 | 282 |  | 
 | 283 | status_t AudioFlinger::TrackHandle::setMediaTimeTransform( | 
 | 284 |     const LinearTransform& xform, int target) { | 
 | 285 |  | 
 | 286 |     if (!mTrack->isTimedTrack()) | 
 | 287 |         return INVALID_OPERATION; | 
 | 288 |  | 
 | 289 |     PlaybackThread::TimedTrack* tt = | 
 | 290 |             reinterpret_cast<PlaybackThread::TimedTrack*>(mTrack.get()); | 
 | 291 |     return tt->setMediaTimeTransform( | 
 | 292 |         xform, static_cast<TimedAudioTrack::TargetTimeline>(target)); | 
 | 293 | } | 
 | 294 |  | 
 | 295 | status_t AudioFlinger::TrackHandle::onTransact( | 
 | 296 |     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) | 
 | 297 | { | 
 | 298 |     return BnAudioTrack::onTransact(code, data, reply, flags); | 
 | 299 | } | 
 | 300 |  | 
 | 301 | // ---------------------------------------------------------------------------- | 
 | 302 |  | 
 | 303 | // Track constructor must be called with AudioFlinger::mLock and ThreadBase::mLock held | 
 | 304 | AudioFlinger::PlaybackThread::Track::Track( | 
 | 305 |             PlaybackThread *thread, | 
 | 306 |             const sp<Client>& client, | 
 | 307 |             audio_stream_type_t streamType, | 
 | 308 |             uint32_t sampleRate, | 
 | 309 |             audio_format_t format, | 
 | 310 |             audio_channel_mask_t channelMask, | 
 | 311 |             size_t frameCount, | 
 | 312 |             const sp<IMemory>& sharedBuffer, | 
 | 313 |             int sessionId, | 
 | 314 |             IAudioFlinger::track_flags_t flags) | 
 | 315 |     :   TrackBase(thread, client, sampleRate, format, channelMask, frameCount, sharedBuffer, | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 316 |             sessionId, true /*isOut*/), | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 317 |     mFillingUpStatus(FS_INVALID), | 
 | 318 |     // mRetryCount initialized later when needed | 
 | 319 |     mSharedBuffer(sharedBuffer), | 
 | 320 |     mStreamType(streamType), | 
 | 321 |     mName(-1),  // see note below | 
 | 322 |     mMainBuffer(thread->mixBuffer()), | 
 | 323 |     mAuxBuffer(NULL), | 
 | 324 |     mAuxEffectId(0), mHasVolumeController(false), | 
 | 325 |     mPresentationCompleteFrames(0), | 
 | 326 |     mFlags(flags), | 
 | 327 |     mFastIndex(-1), | 
 | 328 |     mUnderrunCount(0), | 
| Glenn Kasten | 5736c35 | 2012-12-04 12:12:34 -0800 | [diff] [blame] | 329 |     mCachedVolume(1.0), | 
 | 330 |     mIsInvalid(false) | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 331 | { | 
 | 332 |     if (mCblk != NULL) { | 
 | 333 |         // to avoid leaking a track name, do not allocate one unless there is an mCblk | 
 | 334 |         mName = thread->getTrackName_l(channelMask, sessionId); | 
 | 335 |         mCblk->mName = mName; | 
 | 336 |         if (mName < 0) { | 
 | 337 |             ALOGE("no more track names available"); | 
 | 338 |             return; | 
 | 339 |         } | 
 | 340 |         // only allocate a fast track index if we were able to allocate a normal track name | 
 | 341 |         if (flags & IAudioFlinger::TRACK_FAST) { | 
 | 342 |             ALOG_ASSERT(thread->mFastTrackAvailMask != 0); | 
 | 343 |             int i = __builtin_ctz(thread->mFastTrackAvailMask); | 
 | 344 |             ALOG_ASSERT(0 < i && i < (int)FastMixerState::kMaxFastTracks); | 
 | 345 |             // FIXME This is too eager.  We allocate a fast track index before the | 
 | 346 |             //       fast track becomes active.  Since fast tracks are a scarce resource, | 
 | 347 |             //       this means we are potentially denying other more important fast tracks from | 
 | 348 |             //       being created.  It would be better to allocate the index dynamically. | 
 | 349 |             mFastIndex = i; | 
 | 350 |             mCblk->mName = i; | 
 | 351 |             // Read the initial underruns because this field is never cleared by the fast mixer | 
 | 352 |             mObservedUnderruns = thread->getFastTrackUnderruns(i); | 
 | 353 |             thread->mFastTrackAvailMask &= ~(1 << i); | 
 | 354 |         } | 
 | 355 |     } | 
 | 356 |     ALOGV("Track constructor name %d, calling pid %d", mName, | 
 | 357 |             IPCThreadState::self()->getCallingPid()); | 
 | 358 | } | 
 | 359 |  | 
 | 360 | AudioFlinger::PlaybackThread::Track::~Track() | 
 | 361 | { | 
 | 362 |     ALOGV("PlaybackThread::Track destructor"); | 
 | 363 | } | 
 | 364 |  | 
 | 365 | void AudioFlinger::PlaybackThread::Track::destroy() | 
 | 366 | { | 
 | 367 |     // NOTE: destroyTrack_l() can remove a strong reference to this Track | 
 | 368 |     // by removing it from mTracks vector, so there is a risk that this Tracks's | 
 | 369 |     // destructor is called. As the destructor needs to lock mLock, | 
 | 370 |     // we must acquire a strong reference on this Track before locking mLock | 
 | 371 |     // here so that the destructor is called only when exiting this function. | 
 | 372 |     // On the other hand, as long as Track::destroy() is only called by | 
 | 373 |     // TrackHandle destructor, the TrackHandle still holds a strong ref on | 
 | 374 |     // this Track with its member mTrack. | 
 | 375 |     sp<Track> keep(this); | 
 | 376 |     { // scope for mLock | 
 | 377 |         sp<ThreadBase> thread = mThread.promote(); | 
 | 378 |         if (thread != 0) { | 
 | 379 |             if (!isOutputTrack()) { | 
 | 380 |                 if (mState == ACTIVE || mState == RESUMING) { | 
 | 381 |                     AudioSystem::stopOutput(thread->id(), mStreamType, mSessionId); | 
 | 382 |  | 
 | 383 | #ifdef ADD_BATTERY_DATA | 
 | 384 |                     // to track the speaker usage | 
 | 385 |                     addBatteryData(IMediaPlayerService::kBatteryDataAudioFlingerStop); | 
 | 386 | #endif | 
 | 387 |                 } | 
 | 388 |                 AudioSystem::releaseOutput(thread->id()); | 
 | 389 |             } | 
 | 390 |             Mutex::Autolock _l(thread->mLock); | 
 | 391 |             PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); | 
 | 392 |             playbackThread->destroyTrack_l(this); | 
 | 393 |         } | 
 | 394 |     } | 
 | 395 | } | 
 | 396 |  | 
 | 397 | /*static*/ void AudioFlinger::PlaybackThread::Track::appendDumpHeader(String8& result) | 
 | 398 | { | 
| Glenn Kasten | e4756fe | 2012-11-29 13:38:14 -0800 | [diff] [blame] | 399 |     result.append("   Name Client Type Fmt Chn mask   Session StpCnt fCount S F SRate  " | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 400 |                   "L dB  R dB    Server      User     Main buf    Aux Buf  Flags Underruns\n"); | 
 | 401 | } | 
 | 402 |  | 
 | 403 | void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size) | 
 | 404 | { | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 405 |     uint32_t vlr = mServerProxy->getVolumeLR(); | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 406 |     if (isFastTrack()) { | 
 | 407 |         sprintf(buffer, "   F %2d", mFastIndex); | 
 | 408 |     } else { | 
 | 409 |         sprintf(buffer, "   %4d", mName - AudioMixer::TRACK0); | 
 | 410 |     } | 
 | 411 |     track_state state = mState; | 
 | 412 |     char stateChar; | 
 | 413 |     switch (state) { | 
 | 414 |     case IDLE: | 
 | 415 |         stateChar = 'I'; | 
 | 416 |         break; | 
 | 417 |     case TERMINATED: | 
 | 418 |         stateChar = 'T'; | 
 | 419 |         break; | 
 | 420 |     case STOPPING_1: | 
 | 421 |         stateChar = 's'; | 
 | 422 |         break; | 
 | 423 |     case STOPPING_2: | 
 | 424 |         stateChar = '5'; | 
 | 425 |         break; | 
 | 426 |     case STOPPED: | 
 | 427 |         stateChar = 'S'; | 
 | 428 |         break; | 
 | 429 |     case RESUMING: | 
 | 430 |         stateChar = 'R'; | 
 | 431 |         break; | 
 | 432 |     case ACTIVE: | 
 | 433 |         stateChar = 'A'; | 
 | 434 |         break; | 
 | 435 |     case PAUSING: | 
 | 436 |         stateChar = 'p'; | 
 | 437 |         break; | 
 | 438 |     case PAUSED: | 
 | 439 |         stateChar = 'P'; | 
 | 440 |         break; | 
 | 441 |     case FLUSHED: | 
 | 442 |         stateChar = 'F'; | 
 | 443 |         break; | 
 | 444 |     default: | 
 | 445 |         stateChar = '?'; | 
 | 446 |         break; | 
 | 447 |     } | 
 | 448 |     char nowInUnderrun; | 
 | 449 |     switch (mObservedUnderruns.mBitFields.mMostRecent) { | 
 | 450 |     case UNDERRUN_FULL: | 
 | 451 |         nowInUnderrun = ' '; | 
 | 452 |         break; | 
 | 453 |     case UNDERRUN_PARTIAL: | 
 | 454 |         nowInUnderrun = '<'; | 
 | 455 |         break; | 
 | 456 |     case UNDERRUN_EMPTY: | 
 | 457 |         nowInUnderrun = '*'; | 
 | 458 |         break; | 
 | 459 |     default: | 
 | 460 |         nowInUnderrun = '?'; | 
 | 461 |         break; | 
 | 462 |     } | 
| Glenn Kasten | e4756fe | 2012-11-29 13:38:14 -0800 | [diff] [blame] | 463 |     snprintf(&buffer[7], size-7, " %6d %4u %3u 0x%08x %7u %6u %6u %1c %1d %5u %5.2g %5.2g  " | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 464 |             "0x%08x 0x%08x 0x%08x 0x%08x %#5x %9u%c\n", | 
 | 465 |             (mClient == 0) ? getpid_cached : mClient->pid(), | 
 | 466 |             mStreamType, | 
 | 467 |             mFormat, | 
 | 468 |             mChannelMask, | 
 | 469 |             mSessionId, | 
 | 470 |             mStepCount, | 
 | 471 |             mFrameCount, | 
 | 472 |             stateChar, | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 473 |             mFillingUpStatus, | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 474 |             mServerProxy->getSampleRate(), | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 475 |             20.0 * log10((vlr & 0xFFFF) / 4096.0), | 
 | 476 |             20.0 * log10((vlr >> 16) / 4096.0), | 
 | 477 |             mCblk->server, | 
 | 478 |             mCblk->user, | 
 | 479 |             (int)mMainBuffer, | 
 | 480 |             (int)mAuxBuffer, | 
 | 481 |             mCblk->flags, | 
 | 482 |             mUnderrunCount, | 
 | 483 |             nowInUnderrun); | 
 | 484 | } | 
 | 485 |  | 
 | 486 | // AudioBufferProvider interface | 
 | 487 | status_t AudioFlinger::PlaybackThread::Track::getNextBuffer( | 
 | 488 |         AudioBufferProvider::Buffer* buffer, int64_t pts) | 
 | 489 | { | 
 | 490 |     audio_track_cblk_t* cblk = this->cblk(); | 
 | 491 |     uint32_t framesReady; | 
 | 492 |     uint32_t framesReq = buffer->frameCount; | 
 | 493 |  | 
 | 494 |     // Check if last stepServer failed, try to step now | 
 | 495 |     if (mStepServerFailed) { | 
 | 496 |         // FIXME When called by fast mixer, this takes a mutex with tryLock(). | 
 | 497 |         //       Since the fast mixer is higher priority than client callback thread, | 
 | 498 |         //       it does not result in priority inversion for client. | 
 | 499 |         //       But a non-blocking solution would be preferable to avoid | 
 | 500 |         //       fast mixer being unable to tryLock(), and | 
 | 501 |         //       to avoid the extra context switches if the client wakes up, | 
 | 502 |         //       discovers the mutex is locked, then has to wait for fast mixer to unlock. | 
 | 503 |         if (!step())  goto getNextBuffer_exit; | 
 | 504 |         ALOGV("stepServer recovered"); | 
 | 505 |         mStepServerFailed = false; | 
 | 506 |     } | 
 | 507 |  | 
 | 508 |     // FIXME Same as above | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 509 |     framesReady = mServerProxy->framesReady(); | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 510 |  | 
 | 511 |     if (CC_LIKELY(framesReady)) { | 
 | 512 |         uint32_t s = cblk->server; | 
 | 513 |         uint32_t bufferEnd = cblk->serverBase + mFrameCount; | 
 | 514 |  | 
 | 515 |         bufferEnd = (cblk->loopEnd < bufferEnd) ? cblk->loopEnd : bufferEnd; | 
 | 516 |         if (framesReq > framesReady) { | 
 | 517 |             framesReq = framesReady; | 
 | 518 |         } | 
 | 519 |         if (framesReq > bufferEnd - s) { | 
 | 520 |             framesReq = bufferEnd - s; | 
 | 521 |         } | 
 | 522 |  | 
 | 523 |         buffer->raw = getBuffer(s, framesReq); | 
 | 524 |         buffer->frameCount = framesReq; | 
 | 525 |         return NO_ERROR; | 
 | 526 |     } | 
 | 527 |  | 
 | 528 | getNextBuffer_exit: | 
 | 529 |     buffer->raw = NULL; | 
 | 530 |     buffer->frameCount = 0; | 
 | 531 |     ALOGV("getNextBuffer() no more data for track %d on thread %p", mName, mThread.unsafe_get()); | 
 | 532 |     return NOT_ENOUGH_DATA; | 
 | 533 | } | 
 | 534 |  | 
 | 535 | // Note that framesReady() takes a mutex on the control block using tryLock(). | 
 | 536 | // This could result in priority inversion if framesReady() is called by the normal mixer, | 
 | 537 | // as the normal mixer thread runs at lower | 
 | 538 | // priority than the client's callback thread:  there is a short window within framesReady() | 
 | 539 | // during which the normal mixer could be preempted, and the client callback would block. | 
 | 540 | // Another problem can occur if framesReady() is called by the fast mixer: | 
 | 541 | // the tryLock() could block for up to 1 ms, and a sequence of these could delay fast mixer. | 
 | 542 | // FIXME Replace AudioTrackShared control block implementation by a non-blocking FIFO queue. | 
 | 543 | size_t AudioFlinger::PlaybackThread::Track::framesReady() const { | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 544 |     return mServerProxy->framesReady(); | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 545 | } | 
 | 546 |  | 
 | 547 | // Don't call for fast tracks; the framesReady() could result in priority inversion | 
 | 548 | bool AudioFlinger::PlaybackThread::Track::isReady() const { | 
 | 549 |     if (mFillingUpStatus != FS_FILLING || isStopped() || isPausing()) { | 
 | 550 |         return true; | 
 | 551 |     } | 
 | 552 |  | 
 | 553 |     if (framesReady() >= mFrameCount || | 
 | 554 |             (mCblk->flags & CBLK_FORCEREADY)) { | 
 | 555 |         mFillingUpStatus = FS_FILLED; | 
 | 556 |         android_atomic_and(~CBLK_FORCEREADY, &mCblk->flags); | 
 | 557 |         return true; | 
 | 558 |     } | 
 | 559 |     return false; | 
 | 560 | } | 
 | 561 |  | 
 | 562 | status_t AudioFlinger::PlaybackThread::Track::start(AudioSystem::sync_event_t event, | 
 | 563 |                                                     int triggerSession) | 
 | 564 | { | 
 | 565 |     status_t status = NO_ERROR; | 
 | 566 |     ALOGV("start(%d), calling pid %d session %d", | 
 | 567 |             mName, IPCThreadState::self()->getCallingPid(), mSessionId); | 
 | 568 |  | 
 | 569 |     sp<ThreadBase> thread = mThread.promote(); | 
 | 570 |     if (thread != 0) { | 
 | 571 |         Mutex::Autolock _l(thread->mLock); | 
| Glenn Kasten | 7f5d335 | 2013-02-15 23:55:04 +0000 | [diff] [blame] | 572 |         thread->mNBLogWriter->logf("start mName=%d", mName); | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 573 |         track_state state = mState; | 
 | 574 |         // here the track could be either new, or restarted | 
 | 575 |         // in both cases "unstop" the track | 
 | 576 |         if (mState == PAUSED) { | 
 | 577 |             mState = TrackBase::RESUMING; | 
 | 578 |             ALOGV("PAUSED => RESUMING (%d) on thread %p", mName, this); | 
 | 579 |         } else { | 
 | 580 |             mState = TrackBase::ACTIVE; | 
 | 581 |             ALOGV("? => ACTIVE (%d) on thread %p", mName, this); | 
 | 582 |         } | 
 | 583 |  | 
 | 584 |         if (!isOutputTrack() && state != ACTIVE && state != RESUMING) { | 
 | 585 |             thread->mLock.unlock(); | 
 | 586 |             status = AudioSystem::startOutput(thread->id(), mStreamType, mSessionId); | 
 | 587 |             thread->mLock.lock(); | 
 | 588 |  | 
 | 589 | #ifdef ADD_BATTERY_DATA | 
 | 590 |             // to track the speaker usage | 
 | 591 |             if (status == NO_ERROR) { | 
 | 592 |                 addBatteryData(IMediaPlayerService::kBatteryDataAudioFlingerStart); | 
 | 593 |             } | 
 | 594 | #endif | 
 | 595 |         } | 
 | 596 |         if (status == NO_ERROR) { | 
 | 597 |             PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); | 
 | 598 |             playbackThread->addTrack_l(this); | 
 | 599 |         } else { | 
 | 600 |             mState = state; | 
 | 601 |             triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE); | 
 | 602 |         } | 
 | 603 |     } else { | 
 | 604 |         status = BAD_VALUE; | 
 | 605 |     } | 
 | 606 |     return status; | 
 | 607 | } | 
 | 608 |  | 
 | 609 | void AudioFlinger::PlaybackThread::Track::stop() | 
 | 610 | { | 
 | 611 |     ALOGV("stop(%d), calling pid %d", mName, IPCThreadState::self()->getCallingPid()); | 
 | 612 |     sp<ThreadBase> thread = mThread.promote(); | 
 | 613 |     if (thread != 0) { | 
 | 614 |         Mutex::Autolock _l(thread->mLock); | 
| Glenn Kasten | 7f5d335 | 2013-02-15 23:55:04 +0000 | [diff] [blame] | 615 |         thread->mNBLogWriter->logf("stop mName=%d", mName); | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 616 |         track_state state = mState; | 
 | 617 |         if (state == RESUMING || state == ACTIVE || state == PAUSING || state == PAUSED) { | 
 | 618 |             // If the track is not active (PAUSED and buffers full), flush buffers | 
 | 619 |             PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); | 
 | 620 |             if (playbackThread->mActiveTracks.indexOf(this) < 0) { | 
 | 621 |                 reset(); | 
 | 622 |                 mState = STOPPED; | 
 | 623 |             } else if (!isFastTrack()) { | 
 | 624 |                 mState = STOPPED; | 
 | 625 |             } else { | 
 | 626 |                 // prepareTracks_l() will set state to STOPPING_2 after next underrun, | 
 | 627 |                 // and then to STOPPED and reset() when presentation is complete | 
 | 628 |                 mState = STOPPING_1; | 
 | 629 |             } | 
 | 630 |             ALOGV("not stopping/stopped => stopping/stopped (%d) on thread %p", mName, | 
 | 631 |                     playbackThread); | 
 | 632 |         } | 
 | 633 |         if (!isOutputTrack() && (state == ACTIVE || state == RESUMING)) { | 
 | 634 |             thread->mLock.unlock(); | 
 | 635 |             AudioSystem::stopOutput(thread->id(), mStreamType, mSessionId); | 
 | 636 |             thread->mLock.lock(); | 
 | 637 |  | 
 | 638 | #ifdef ADD_BATTERY_DATA | 
 | 639 |             // to track the speaker usage | 
 | 640 |             addBatteryData(IMediaPlayerService::kBatteryDataAudioFlingerStop); | 
 | 641 | #endif | 
 | 642 |         } | 
 | 643 |     } | 
 | 644 | } | 
 | 645 |  | 
 | 646 | void AudioFlinger::PlaybackThread::Track::pause() | 
 | 647 | { | 
 | 648 |     ALOGV("pause(%d), calling pid %d", mName, IPCThreadState::self()->getCallingPid()); | 
 | 649 |     sp<ThreadBase> thread = mThread.promote(); | 
 | 650 |     if (thread != 0) { | 
 | 651 |         Mutex::Autolock _l(thread->mLock); | 
| Glenn Kasten | 7f5d335 | 2013-02-15 23:55:04 +0000 | [diff] [blame] | 652 |         thread->mNBLogWriter->logf("pause mName=%d", mName); | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 653 |         if (mState == ACTIVE || mState == RESUMING) { | 
 | 654 |             mState = PAUSING; | 
 | 655 |             ALOGV("ACTIVE/RESUMING => PAUSING (%d) on thread %p", mName, thread.get()); | 
 | 656 |             if (!isOutputTrack()) { | 
 | 657 |                 thread->mLock.unlock(); | 
 | 658 |                 AudioSystem::stopOutput(thread->id(), mStreamType, mSessionId); | 
 | 659 |                 thread->mLock.lock(); | 
 | 660 |  | 
 | 661 | #ifdef ADD_BATTERY_DATA | 
 | 662 |                 // to track the speaker usage | 
 | 663 |                 addBatteryData(IMediaPlayerService::kBatteryDataAudioFlingerStop); | 
 | 664 | #endif | 
 | 665 |             } | 
 | 666 |         } | 
 | 667 |     } | 
 | 668 | } | 
 | 669 |  | 
 | 670 | void AudioFlinger::PlaybackThread::Track::flush() | 
 | 671 | { | 
 | 672 |     ALOGV("flush(%d)", mName); | 
 | 673 |     sp<ThreadBase> thread = mThread.promote(); | 
 | 674 |     if (thread != 0) { | 
 | 675 |         Mutex::Autolock _l(thread->mLock); | 
| Glenn Kasten | 7f5d335 | 2013-02-15 23:55:04 +0000 | [diff] [blame] | 676 |         thread->mNBLogWriter->logf("flush mName=%d", mName); | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 677 |         if (mState != STOPPING_1 && mState != STOPPING_2 && mState != STOPPED && mState != PAUSED && | 
 | 678 |                 mState != PAUSING && mState != IDLE && mState != FLUSHED) { | 
 | 679 |             return; | 
 | 680 |         } | 
 | 681 |         // No point remaining in PAUSED state after a flush => go to | 
 | 682 |         // FLUSHED state | 
 | 683 |         mState = FLUSHED; | 
 | 684 |         // do not reset the track if it is still in the process of being stopped or paused. | 
 | 685 |         // this will be done by prepareTracks_l() when the track is stopped. | 
 | 686 |         // prepareTracks_l() will see mState == FLUSHED, then | 
 | 687 |         // remove from active track list, reset(), and trigger presentation complete | 
 | 688 |         PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); | 
 | 689 |         if (playbackThread->mActiveTracks.indexOf(this) < 0) { | 
 | 690 |             reset(); | 
 | 691 |         } | 
 | 692 |     } | 
 | 693 | } | 
 | 694 |  | 
 | 695 | void AudioFlinger::PlaybackThread::Track::reset() | 
 | 696 | { | 
 | 697 |     // Do not reset twice to avoid discarding data written just after a flush and before | 
 | 698 |     // the audioflinger thread detects the track is stopped. | 
 | 699 |     if (!mResetDone) { | 
 | 700 |         TrackBase::reset(); | 
 | 701 |         // Force underrun condition to avoid false underrun callback until first data is | 
 | 702 |         // written to buffer | 
 | 703 |         android_atomic_and(~CBLK_FORCEREADY, &mCblk->flags); | 
 | 704 |         android_atomic_or(CBLK_UNDERRUN, &mCblk->flags); | 
 | 705 |         mFillingUpStatus = FS_FILLING; | 
 | 706 |         mResetDone = true; | 
 | 707 |         if (mState == FLUSHED) { | 
 | 708 |             mState = IDLE; | 
 | 709 |         } | 
 | 710 |     } | 
 | 711 | } | 
 | 712 |  | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 713 | status_t AudioFlinger::PlaybackThread::Track::attachAuxEffect(int EffectId) | 
 | 714 | { | 
 | 715 |     status_t status = DEAD_OBJECT; | 
 | 716 |     sp<ThreadBase> thread = mThread.promote(); | 
 | 717 |     if (thread != 0) { | 
 | 718 |         PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); | 
 | 719 |         sp<AudioFlinger> af = mClient->audioFlinger(); | 
 | 720 |  | 
 | 721 |         Mutex::Autolock _l(af->mLock); | 
 | 722 |  | 
 | 723 |         sp<PlaybackThread> srcThread = af->getEffectThread_l(AUDIO_SESSION_OUTPUT_MIX, EffectId); | 
 | 724 |  | 
 | 725 |         if (EffectId != 0 && srcThread != 0 && playbackThread != srcThread.get()) { | 
 | 726 |             Mutex::Autolock _dl(playbackThread->mLock); | 
 | 727 |             Mutex::Autolock _sl(srcThread->mLock); | 
 | 728 |             sp<EffectChain> chain = srcThread->getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX); | 
 | 729 |             if (chain == 0) { | 
 | 730 |                 return INVALID_OPERATION; | 
 | 731 |             } | 
 | 732 |  | 
 | 733 |             sp<EffectModule> effect = chain->getEffectFromId_l(EffectId); | 
 | 734 |             if (effect == 0) { | 
 | 735 |                 return INVALID_OPERATION; | 
 | 736 |             } | 
 | 737 |             srcThread->removeEffect_l(effect); | 
 | 738 |             playbackThread->addEffect_l(effect); | 
 | 739 |             // removeEffect_l() has stopped the effect if it was active so it must be restarted | 
 | 740 |             if (effect->state() == EffectModule::ACTIVE || | 
 | 741 |                     effect->state() == EffectModule::STOPPING) { | 
 | 742 |                 effect->start(); | 
 | 743 |             } | 
 | 744 |  | 
 | 745 |             sp<EffectChain> dstChain = effect->chain().promote(); | 
 | 746 |             if (dstChain == 0) { | 
 | 747 |                 srcThread->addEffect_l(effect); | 
 | 748 |                 return INVALID_OPERATION; | 
 | 749 |             } | 
 | 750 |             AudioSystem::unregisterEffect(effect->id()); | 
 | 751 |             AudioSystem::registerEffect(&effect->desc(), | 
 | 752 |                                         srcThread->id(), | 
 | 753 |                                         dstChain->strategy(), | 
 | 754 |                                         AUDIO_SESSION_OUTPUT_MIX, | 
 | 755 |                                         effect->id()); | 
 | 756 |         } | 
 | 757 |         status = playbackThread->attachAuxEffect(this, EffectId); | 
 | 758 |     } | 
 | 759 |     return status; | 
 | 760 | } | 
 | 761 |  | 
 | 762 | void AudioFlinger::PlaybackThread::Track::setAuxBuffer(int EffectId, int32_t *buffer) | 
 | 763 | { | 
 | 764 |     mAuxEffectId = EffectId; | 
 | 765 |     mAuxBuffer = buffer; | 
 | 766 | } | 
 | 767 |  | 
 | 768 | bool AudioFlinger::PlaybackThread::Track::presentationComplete(size_t framesWritten, | 
 | 769 |                                                          size_t audioHalFrames) | 
 | 770 | { | 
 | 771 |     // a track is considered presented when the total number of frames written to audio HAL | 
 | 772 |     // corresponds to the number of frames written when presentationComplete() is called for the | 
 | 773 |     // first time (mPresentationCompleteFrames == 0) plus the buffer filling status at that time. | 
 | 774 |     if (mPresentationCompleteFrames == 0) { | 
 | 775 |         mPresentationCompleteFrames = framesWritten + audioHalFrames; | 
 | 776 |         ALOGV("presentationComplete() reset: mPresentationCompleteFrames %d audioHalFrames %d", | 
 | 777 |                   mPresentationCompleteFrames, audioHalFrames); | 
 | 778 |     } | 
 | 779 |     if (framesWritten >= mPresentationCompleteFrames) { | 
 | 780 |         ALOGV("presentationComplete() session %d complete: framesWritten %d", | 
 | 781 |                   mSessionId, framesWritten); | 
 | 782 |         triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE); | 
 | 783 |         return true; | 
 | 784 |     } | 
 | 785 |     return false; | 
 | 786 | } | 
 | 787 |  | 
 | 788 | void AudioFlinger::PlaybackThread::Track::triggerEvents(AudioSystem::sync_event_t type) | 
 | 789 | { | 
 | 790 |     for (int i = 0; i < (int)mSyncEvents.size(); i++) { | 
 | 791 |         if (mSyncEvents[i]->type() == type) { | 
 | 792 |             mSyncEvents[i]->trigger(); | 
 | 793 |             mSyncEvents.removeAt(i); | 
 | 794 |             i--; | 
 | 795 |         } | 
 | 796 |     } | 
 | 797 | } | 
 | 798 |  | 
 | 799 | // implement VolumeBufferProvider interface | 
 | 800 |  | 
 | 801 | uint32_t AudioFlinger::PlaybackThread::Track::getVolumeLR() | 
 | 802 | { | 
 | 803 |     // called by FastMixer, so not allowed to take any locks, block, or do I/O including logs | 
 | 804 |     ALOG_ASSERT(isFastTrack() && (mCblk != NULL)); | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 805 |     uint32_t vlr = mServerProxy->getVolumeLR(); | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 806 |     uint32_t vl = vlr & 0xFFFF; | 
 | 807 |     uint32_t vr = vlr >> 16; | 
 | 808 |     // track volumes come from shared memory, so can't be trusted and must be clamped | 
 | 809 |     if (vl > MAX_GAIN_INT) { | 
 | 810 |         vl = MAX_GAIN_INT; | 
 | 811 |     } | 
 | 812 |     if (vr > MAX_GAIN_INT) { | 
 | 813 |         vr = MAX_GAIN_INT; | 
 | 814 |     } | 
 | 815 |     // now apply the cached master volume and stream type volume; | 
 | 816 |     // this is trusted but lacks any synchronization or barrier so may be stale | 
 | 817 |     float v = mCachedVolume; | 
 | 818 |     vl *= v; | 
 | 819 |     vr *= v; | 
 | 820 |     // re-combine into U4.16 | 
 | 821 |     vlr = (vr << 16) | (vl & 0xFFFF); | 
 | 822 |     // FIXME look at mute, pause, and stop flags | 
 | 823 |     return vlr; | 
 | 824 | } | 
 | 825 |  | 
 | 826 | status_t AudioFlinger::PlaybackThread::Track::setSyncEvent(const sp<SyncEvent>& event) | 
 | 827 | { | 
 | 828 |     if (mState == TERMINATED || mState == PAUSED || | 
 | 829 |             ((framesReady() == 0) && ((mSharedBuffer != 0) || | 
 | 830 |                                       (mState == STOPPED)))) { | 
 | 831 |         ALOGW("Track::setSyncEvent() in invalid state %d on session %d %s mode, framesReady %d ", | 
 | 832 |               mState, mSessionId, (mSharedBuffer != 0) ? "static" : "stream", framesReady()); | 
 | 833 |         event->cancel(); | 
 | 834 |         return INVALID_OPERATION; | 
 | 835 |     } | 
 | 836 |     (void) TrackBase::setSyncEvent(event); | 
 | 837 |     return NO_ERROR; | 
 | 838 | } | 
 | 839 |  | 
| Glenn Kasten | 5736c35 | 2012-12-04 12:12:34 -0800 | [diff] [blame] | 840 | void AudioFlinger::PlaybackThread::Track::invalidate() | 
 | 841 | { | 
 | 842 |     // FIXME should use proxy | 
 | 843 |     android_atomic_or(CBLK_INVALID, &mCblk->flags); | 
 | 844 |     mCblk->cv.signal(); | 
 | 845 |     mIsInvalid = true; | 
 | 846 | } | 
 | 847 |  | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 848 | // ---------------------------------------------------------------------------- | 
 | 849 |  | 
 | 850 | sp<AudioFlinger::PlaybackThread::TimedTrack> | 
 | 851 | AudioFlinger::PlaybackThread::TimedTrack::create( | 
 | 852 |             PlaybackThread *thread, | 
 | 853 |             const sp<Client>& client, | 
 | 854 |             audio_stream_type_t streamType, | 
 | 855 |             uint32_t sampleRate, | 
 | 856 |             audio_format_t format, | 
 | 857 |             audio_channel_mask_t channelMask, | 
 | 858 |             size_t frameCount, | 
 | 859 |             const sp<IMemory>& sharedBuffer, | 
 | 860 |             int sessionId) { | 
 | 861 |     if (!client->reserveTimedTrack()) | 
 | 862 |         return 0; | 
 | 863 |  | 
 | 864 |     return new TimedTrack( | 
 | 865 |         thread, client, streamType, sampleRate, format, channelMask, frameCount, | 
 | 866 |         sharedBuffer, sessionId); | 
 | 867 | } | 
 | 868 |  | 
 | 869 | AudioFlinger::PlaybackThread::TimedTrack::TimedTrack( | 
 | 870 |             PlaybackThread *thread, | 
 | 871 |             const sp<Client>& client, | 
 | 872 |             audio_stream_type_t streamType, | 
 | 873 |             uint32_t sampleRate, | 
 | 874 |             audio_format_t format, | 
 | 875 |             audio_channel_mask_t channelMask, | 
 | 876 |             size_t frameCount, | 
 | 877 |             const sp<IMemory>& sharedBuffer, | 
 | 878 |             int sessionId) | 
 | 879 |     : Track(thread, client, streamType, sampleRate, format, channelMask, | 
 | 880 |             frameCount, sharedBuffer, sessionId, IAudioFlinger::TRACK_TIMED), | 
 | 881 |       mQueueHeadInFlight(false), | 
 | 882 |       mTrimQueueHeadOnRelease(false), | 
 | 883 |       mFramesPendingInQueue(0), | 
 | 884 |       mTimedSilenceBuffer(NULL), | 
 | 885 |       mTimedSilenceBufferSize(0), | 
 | 886 |       mTimedAudioOutputOnTime(false), | 
 | 887 |       mMediaTimeTransformValid(false) | 
 | 888 | { | 
 | 889 |     LocalClock lc; | 
 | 890 |     mLocalTimeFreq = lc.getLocalFreq(); | 
 | 891 |  | 
 | 892 |     mLocalTimeToSampleTransform.a_zero = 0; | 
 | 893 |     mLocalTimeToSampleTransform.b_zero = 0; | 
 | 894 |     mLocalTimeToSampleTransform.a_to_b_numer = sampleRate; | 
 | 895 |     mLocalTimeToSampleTransform.a_to_b_denom = mLocalTimeFreq; | 
 | 896 |     LinearTransform::reduce(&mLocalTimeToSampleTransform.a_to_b_numer, | 
 | 897 |                             &mLocalTimeToSampleTransform.a_to_b_denom); | 
 | 898 |  | 
 | 899 |     mMediaTimeToSampleTransform.a_zero = 0; | 
 | 900 |     mMediaTimeToSampleTransform.b_zero = 0; | 
 | 901 |     mMediaTimeToSampleTransform.a_to_b_numer = sampleRate; | 
 | 902 |     mMediaTimeToSampleTransform.a_to_b_denom = 1000000; | 
 | 903 |     LinearTransform::reduce(&mMediaTimeToSampleTransform.a_to_b_numer, | 
 | 904 |                             &mMediaTimeToSampleTransform.a_to_b_denom); | 
 | 905 | } | 
 | 906 |  | 
 | 907 | AudioFlinger::PlaybackThread::TimedTrack::~TimedTrack() { | 
 | 908 |     mClient->releaseTimedTrack(); | 
 | 909 |     delete [] mTimedSilenceBuffer; | 
 | 910 | } | 
 | 911 |  | 
 | 912 | status_t AudioFlinger::PlaybackThread::TimedTrack::allocateTimedBuffer( | 
 | 913 |     size_t size, sp<IMemory>* buffer) { | 
 | 914 |  | 
 | 915 |     Mutex::Autolock _l(mTimedBufferQueueLock); | 
 | 916 |  | 
 | 917 |     trimTimedBufferQueue_l(); | 
 | 918 |  | 
 | 919 |     // lazily initialize the shared memory heap for timed buffers | 
 | 920 |     if (mTimedMemoryDealer == NULL) { | 
 | 921 |         const int kTimedBufferHeapSize = 512 << 10; | 
 | 922 |  | 
 | 923 |         mTimedMemoryDealer = new MemoryDealer(kTimedBufferHeapSize, | 
 | 924 |                                               "AudioFlingerTimed"); | 
 | 925 |         if (mTimedMemoryDealer == NULL) | 
 | 926 |             return NO_MEMORY; | 
 | 927 |     } | 
 | 928 |  | 
 | 929 |     sp<IMemory> newBuffer = mTimedMemoryDealer->allocate(size); | 
 | 930 |     if (newBuffer == NULL) { | 
 | 931 |         newBuffer = mTimedMemoryDealer->allocate(size); | 
 | 932 |         if (newBuffer == NULL) | 
 | 933 |             return NO_MEMORY; | 
 | 934 |     } | 
 | 935 |  | 
 | 936 |     *buffer = newBuffer; | 
 | 937 |     return NO_ERROR; | 
 | 938 | } | 
 | 939 |  | 
 | 940 | // caller must hold mTimedBufferQueueLock | 
 | 941 | void AudioFlinger::PlaybackThread::TimedTrack::trimTimedBufferQueue_l() { | 
 | 942 |     int64_t mediaTimeNow; | 
 | 943 |     { | 
 | 944 |         Mutex::Autolock mttLock(mMediaTimeTransformLock); | 
 | 945 |         if (!mMediaTimeTransformValid) | 
 | 946 |             return; | 
 | 947 |  | 
 | 948 |         int64_t targetTimeNow; | 
 | 949 |         status_t res = (mMediaTimeTransformTarget == TimedAudioTrack::COMMON_TIME) | 
 | 950 |             ? mCCHelper.getCommonTime(&targetTimeNow) | 
 | 951 |             : mCCHelper.getLocalTime(&targetTimeNow); | 
 | 952 |  | 
 | 953 |         if (OK != res) | 
 | 954 |             return; | 
 | 955 |  | 
 | 956 |         if (!mMediaTimeTransform.doReverseTransform(targetTimeNow, | 
 | 957 |                                                     &mediaTimeNow)) { | 
 | 958 |             return; | 
 | 959 |         } | 
 | 960 |     } | 
 | 961 |  | 
 | 962 |     size_t trimEnd; | 
 | 963 |     for (trimEnd = 0; trimEnd < mTimedBufferQueue.size(); trimEnd++) { | 
 | 964 |         int64_t bufEnd; | 
 | 965 |  | 
 | 966 |         if ((trimEnd + 1) < mTimedBufferQueue.size()) { | 
 | 967 |             // We have a next buffer.  Just use its PTS as the PTS of the frame | 
 | 968 |             // following the last frame in this buffer.  If the stream is sparse | 
 | 969 |             // (ie, there are deliberate gaps left in the stream which should be | 
 | 970 |             // filled with silence by the TimedAudioTrack), then this can result | 
 | 971 |             // in one extra buffer being left un-trimmed when it could have | 
 | 972 |             // been.  In general, this is not typical, and we would rather | 
 | 973 |             // optimized away the TS calculation below for the more common case | 
 | 974 |             // where PTSes are contiguous. | 
 | 975 |             bufEnd = mTimedBufferQueue[trimEnd + 1].pts(); | 
 | 976 |         } else { | 
 | 977 |             // We have no next buffer.  Compute the PTS of the frame following | 
 | 978 |             // the last frame in this buffer by computing the duration of of | 
 | 979 |             // this frame in media time units and adding it to the PTS of the | 
 | 980 |             // buffer. | 
 | 981 |             int64_t frameCount = mTimedBufferQueue[trimEnd].buffer()->size() | 
 | 982 |                                / mFrameSize; | 
 | 983 |  | 
 | 984 |             if (!mMediaTimeToSampleTransform.doReverseTransform(frameCount, | 
 | 985 |                                                                 &bufEnd)) { | 
 | 986 |                 ALOGE("Failed to convert frame count of %lld to media time" | 
 | 987 |                       " duration" " (scale factor %d/%u) in %s", | 
 | 988 |                       frameCount, | 
 | 989 |                       mMediaTimeToSampleTransform.a_to_b_numer, | 
 | 990 |                       mMediaTimeToSampleTransform.a_to_b_denom, | 
 | 991 |                       __PRETTY_FUNCTION__); | 
 | 992 |                 break; | 
 | 993 |             } | 
 | 994 |             bufEnd += mTimedBufferQueue[trimEnd].pts(); | 
 | 995 |         } | 
 | 996 |  | 
 | 997 |         if (bufEnd > mediaTimeNow) | 
 | 998 |             break; | 
 | 999 |  | 
 | 1000 |         // Is the buffer we want to use in the middle of a mix operation right | 
 | 1001 |         // now?  If so, don't actually trim it.  Just wait for the releaseBuffer | 
 | 1002 |         // from the mixer which should be coming back shortly. | 
 | 1003 |         if (!trimEnd && mQueueHeadInFlight) { | 
 | 1004 |             mTrimQueueHeadOnRelease = true; | 
 | 1005 |         } | 
 | 1006 |     } | 
 | 1007 |  | 
 | 1008 |     size_t trimStart = mTrimQueueHeadOnRelease ? 1 : 0; | 
 | 1009 |     if (trimStart < trimEnd) { | 
 | 1010 |         // Update the bookkeeping for framesReady() | 
 | 1011 |         for (size_t i = trimStart; i < trimEnd; ++i) { | 
 | 1012 |             updateFramesPendingAfterTrim_l(mTimedBufferQueue[i], "trim"); | 
 | 1013 |         } | 
 | 1014 |  | 
 | 1015 |         // Now actually remove the buffers from the queue. | 
 | 1016 |         mTimedBufferQueue.removeItemsAt(trimStart, trimEnd); | 
 | 1017 |     } | 
 | 1018 | } | 
 | 1019 |  | 
 | 1020 | void AudioFlinger::PlaybackThread::TimedTrack::trimTimedBufferQueueHead_l( | 
 | 1021 |         const char* logTag) { | 
 | 1022 |     ALOG_ASSERT(mTimedBufferQueue.size() > 0, | 
 | 1023 |                 "%s called (reason \"%s\"), but timed buffer queue has no" | 
 | 1024 |                 " elements to trim.", __FUNCTION__, logTag); | 
 | 1025 |  | 
 | 1026 |     updateFramesPendingAfterTrim_l(mTimedBufferQueue[0], logTag); | 
 | 1027 |     mTimedBufferQueue.removeAt(0); | 
 | 1028 | } | 
 | 1029 |  | 
 | 1030 | void AudioFlinger::PlaybackThread::TimedTrack::updateFramesPendingAfterTrim_l( | 
 | 1031 |         const TimedBuffer& buf, | 
 | 1032 |         const char* logTag) { | 
 | 1033 |     uint32_t bufBytes        = buf.buffer()->size(); | 
 | 1034 |     uint32_t consumedAlready = buf.position(); | 
 | 1035 |  | 
 | 1036 |     ALOG_ASSERT(consumedAlready <= bufBytes, | 
 | 1037 |                 "Bad bookkeeping while updating frames pending.  Timed buffer is" | 
 | 1038 |                 " only %u bytes long, but claims to have consumed %u" | 
 | 1039 |                 " bytes.  (update reason: \"%s\")", | 
 | 1040 |                 bufBytes, consumedAlready, logTag); | 
 | 1041 |  | 
 | 1042 |     uint32_t bufFrames = (bufBytes - consumedAlready) / mFrameSize; | 
 | 1043 |     ALOG_ASSERT(mFramesPendingInQueue >= bufFrames, | 
 | 1044 |                 "Bad bookkeeping while updating frames pending.  Should have at" | 
 | 1045 |                 " least %u queued frames, but we think we have only %u.  (update" | 
 | 1046 |                 " reason: \"%s\")", | 
 | 1047 |                 bufFrames, mFramesPendingInQueue, logTag); | 
 | 1048 |  | 
 | 1049 |     mFramesPendingInQueue -= bufFrames; | 
 | 1050 | } | 
 | 1051 |  | 
 | 1052 | status_t AudioFlinger::PlaybackThread::TimedTrack::queueTimedBuffer( | 
 | 1053 |     const sp<IMemory>& buffer, int64_t pts) { | 
 | 1054 |  | 
 | 1055 |     { | 
 | 1056 |         Mutex::Autolock mttLock(mMediaTimeTransformLock); | 
 | 1057 |         if (!mMediaTimeTransformValid) | 
 | 1058 |             return INVALID_OPERATION; | 
 | 1059 |     } | 
 | 1060 |  | 
 | 1061 |     Mutex::Autolock _l(mTimedBufferQueueLock); | 
 | 1062 |  | 
 | 1063 |     uint32_t bufFrames = buffer->size() / mFrameSize; | 
 | 1064 |     mFramesPendingInQueue += bufFrames; | 
 | 1065 |     mTimedBufferQueue.add(TimedBuffer(buffer, pts)); | 
 | 1066 |  | 
 | 1067 |     return NO_ERROR; | 
 | 1068 | } | 
 | 1069 |  | 
 | 1070 | status_t AudioFlinger::PlaybackThread::TimedTrack::setMediaTimeTransform( | 
 | 1071 |     const LinearTransform& xform, TimedAudioTrack::TargetTimeline target) { | 
 | 1072 |  | 
 | 1073 |     ALOGVV("setMediaTimeTransform az=%lld bz=%lld n=%d d=%u tgt=%d", | 
 | 1074 |            xform.a_zero, xform.b_zero, xform.a_to_b_numer, xform.a_to_b_denom, | 
 | 1075 |            target); | 
 | 1076 |  | 
 | 1077 |     if (!(target == TimedAudioTrack::LOCAL_TIME || | 
 | 1078 |           target == TimedAudioTrack::COMMON_TIME)) { | 
 | 1079 |         return BAD_VALUE; | 
 | 1080 |     } | 
 | 1081 |  | 
 | 1082 |     Mutex::Autolock lock(mMediaTimeTransformLock); | 
 | 1083 |     mMediaTimeTransform = xform; | 
 | 1084 |     mMediaTimeTransformTarget = target; | 
 | 1085 |     mMediaTimeTransformValid = true; | 
 | 1086 |  | 
 | 1087 |     return NO_ERROR; | 
 | 1088 | } | 
 | 1089 |  | 
 | 1090 | #define min(a, b) ((a) < (b) ? (a) : (b)) | 
 | 1091 |  | 
 | 1092 | // implementation of getNextBuffer for tracks whose buffers have timestamps | 
 | 1093 | status_t AudioFlinger::PlaybackThread::TimedTrack::getNextBuffer( | 
 | 1094 |     AudioBufferProvider::Buffer* buffer, int64_t pts) | 
 | 1095 | { | 
 | 1096 |     if (pts == AudioBufferProvider::kInvalidPTS) { | 
 | 1097 |         buffer->raw = NULL; | 
 | 1098 |         buffer->frameCount = 0; | 
 | 1099 |         mTimedAudioOutputOnTime = false; | 
 | 1100 |         return INVALID_OPERATION; | 
 | 1101 |     } | 
 | 1102 |  | 
 | 1103 |     Mutex::Autolock _l(mTimedBufferQueueLock); | 
 | 1104 |  | 
 | 1105 |     ALOG_ASSERT(!mQueueHeadInFlight, | 
 | 1106 |                 "getNextBuffer called without releaseBuffer!"); | 
 | 1107 |  | 
 | 1108 |     while (true) { | 
 | 1109 |  | 
 | 1110 |         // if we have no timed buffers, then fail | 
 | 1111 |         if (mTimedBufferQueue.isEmpty()) { | 
 | 1112 |             buffer->raw = NULL; | 
 | 1113 |             buffer->frameCount = 0; | 
 | 1114 |             return NOT_ENOUGH_DATA; | 
 | 1115 |         } | 
 | 1116 |  | 
 | 1117 |         TimedBuffer& head = mTimedBufferQueue.editItemAt(0); | 
 | 1118 |  | 
 | 1119 |         // calculate the PTS of the head of the timed buffer queue expressed in | 
 | 1120 |         // local time | 
 | 1121 |         int64_t headLocalPTS; | 
 | 1122 |         { | 
 | 1123 |             Mutex::Autolock mttLock(mMediaTimeTransformLock); | 
 | 1124 |  | 
 | 1125 |             ALOG_ASSERT(mMediaTimeTransformValid, "media time transform invalid"); | 
 | 1126 |  | 
 | 1127 |             if (mMediaTimeTransform.a_to_b_denom == 0) { | 
 | 1128 |                 // the transform represents a pause, so yield silence | 
 | 1129 |                 timedYieldSilence_l(buffer->frameCount, buffer); | 
 | 1130 |                 return NO_ERROR; | 
 | 1131 |             } | 
 | 1132 |  | 
 | 1133 |             int64_t transformedPTS; | 
 | 1134 |             if (!mMediaTimeTransform.doForwardTransform(head.pts(), | 
 | 1135 |                                                         &transformedPTS)) { | 
 | 1136 |                 // the transform failed.  this shouldn't happen, but if it does | 
 | 1137 |                 // then just drop this buffer | 
 | 1138 |                 ALOGW("timedGetNextBuffer transform failed"); | 
 | 1139 |                 buffer->raw = NULL; | 
 | 1140 |                 buffer->frameCount = 0; | 
 | 1141 |                 trimTimedBufferQueueHead_l("getNextBuffer; no transform"); | 
 | 1142 |                 return NO_ERROR; | 
 | 1143 |             } | 
 | 1144 |  | 
 | 1145 |             if (mMediaTimeTransformTarget == TimedAudioTrack::COMMON_TIME) { | 
 | 1146 |                 if (OK != mCCHelper.commonTimeToLocalTime(transformedPTS, | 
 | 1147 |                                                           &headLocalPTS)) { | 
 | 1148 |                     buffer->raw = NULL; | 
 | 1149 |                     buffer->frameCount = 0; | 
 | 1150 |                     return INVALID_OPERATION; | 
 | 1151 |                 } | 
 | 1152 |             } else { | 
 | 1153 |                 headLocalPTS = transformedPTS; | 
 | 1154 |             } | 
 | 1155 |         } | 
 | 1156 |  | 
 | 1157 |         // adjust the head buffer's PTS to reflect the portion of the head buffer | 
 | 1158 |         // that has already been consumed | 
 | 1159 |         int64_t effectivePTS = headLocalPTS + | 
 | 1160 |                 ((head.position() / mFrameSize) * mLocalTimeFreq / sampleRate()); | 
 | 1161 |  | 
 | 1162 |         // Calculate the delta in samples between the head of the input buffer | 
 | 1163 |         // queue and the start of the next output buffer that will be written. | 
 | 1164 |         // If the transformation fails because of over or underflow, it means | 
 | 1165 |         // that the sample's position in the output stream is so far out of | 
 | 1166 |         // whack that it should just be dropped. | 
 | 1167 |         int64_t sampleDelta; | 
 | 1168 |         if (llabs(effectivePTS - pts) >= (static_cast<int64_t>(1) << 31)) { | 
 | 1169 |             ALOGV("*** head buffer is too far from PTS: dropped buffer"); | 
 | 1170 |             trimTimedBufferQueueHead_l("getNextBuffer, buf pts too far from" | 
 | 1171 |                                        " mix"); | 
 | 1172 |             continue; | 
 | 1173 |         } | 
 | 1174 |         if (!mLocalTimeToSampleTransform.doForwardTransform( | 
 | 1175 |                 (effectivePTS - pts) << 32, &sampleDelta)) { | 
 | 1176 |             ALOGV("*** too late during sample rate transform: dropped buffer"); | 
 | 1177 |             trimTimedBufferQueueHead_l("getNextBuffer, bad local to sample"); | 
 | 1178 |             continue; | 
 | 1179 |         } | 
 | 1180 |  | 
 | 1181 |         ALOGVV("*** getNextBuffer head.pts=%lld head.pos=%d pts=%lld" | 
 | 1182 |                " sampleDelta=[%d.%08x]", | 
 | 1183 |                head.pts(), head.position(), pts, | 
 | 1184 |                static_cast<int32_t>((sampleDelta >= 0 ? 0 : 1) | 
 | 1185 |                    + (sampleDelta >> 32)), | 
 | 1186 |                static_cast<uint32_t>(sampleDelta & 0xFFFFFFFF)); | 
 | 1187 |  | 
 | 1188 |         // if the delta between the ideal placement for the next input sample and | 
 | 1189 |         // the current output position is within this threshold, then we will | 
 | 1190 |         // concatenate the next input samples to the previous output | 
 | 1191 |         const int64_t kSampleContinuityThreshold = | 
 | 1192 |                 (static_cast<int64_t>(sampleRate()) << 32) / 250; | 
 | 1193 |  | 
 | 1194 |         // if this is the first buffer of audio that we're emitting from this track | 
 | 1195 |         // then it should be almost exactly on time. | 
 | 1196 |         const int64_t kSampleStartupThreshold = 1LL << 32; | 
 | 1197 |  | 
 | 1198 |         if ((mTimedAudioOutputOnTime && llabs(sampleDelta) <= kSampleContinuityThreshold) || | 
 | 1199 |            (!mTimedAudioOutputOnTime && llabs(sampleDelta) <= kSampleStartupThreshold)) { | 
 | 1200 |             // the next input is close enough to being on time, so concatenate it | 
 | 1201 |             // with the last output | 
 | 1202 |             timedYieldSamples_l(buffer); | 
 | 1203 |  | 
 | 1204 |             ALOGVV("*** on time: head.pos=%d frameCount=%u", | 
 | 1205 |                     head.position(), buffer->frameCount); | 
 | 1206 |             return NO_ERROR; | 
 | 1207 |         } | 
 | 1208 |  | 
 | 1209 |         // Looks like our output is not on time.  Reset our on timed status. | 
 | 1210 |         // Next time we mix samples from our input queue, then should be within | 
 | 1211 |         // the StartupThreshold. | 
 | 1212 |         mTimedAudioOutputOnTime = false; | 
 | 1213 |         if (sampleDelta > 0) { | 
 | 1214 |             // the gap between the current output position and the proper start of | 
 | 1215 |             // the next input sample is too big, so fill it with silence | 
 | 1216 |             uint32_t framesUntilNextInput = (sampleDelta + 0x80000000) >> 32; | 
 | 1217 |  | 
 | 1218 |             timedYieldSilence_l(framesUntilNextInput, buffer); | 
 | 1219 |             ALOGV("*** silence: frameCount=%u", buffer->frameCount); | 
 | 1220 |             return NO_ERROR; | 
 | 1221 |         } else { | 
 | 1222 |             // the next input sample is late | 
 | 1223 |             uint32_t lateFrames = static_cast<uint32_t>(-((sampleDelta + 0x80000000) >> 32)); | 
 | 1224 |             size_t onTimeSamplePosition = | 
 | 1225 |                     head.position() + lateFrames * mFrameSize; | 
 | 1226 |  | 
 | 1227 |             if (onTimeSamplePosition > head.buffer()->size()) { | 
 | 1228 |                 // all the remaining samples in the head are too late, so | 
 | 1229 |                 // drop it and move on | 
 | 1230 |                 ALOGV("*** too late: dropped buffer"); | 
 | 1231 |                 trimTimedBufferQueueHead_l("getNextBuffer, dropped late buffer"); | 
 | 1232 |                 continue; | 
 | 1233 |             } else { | 
 | 1234 |                 // skip over the late samples | 
 | 1235 |                 head.setPosition(onTimeSamplePosition); | 
 | 1236 |  | 
 | 1237 |                 // yield the available samples | 
 | 1238 |                 timedYieldSamples_l(buffer); | 
 | 1239 |  | 
 | 1240 |                 ALOGV("*** late: head.pos=%d frameCount=%u", head.position(), buffer->frameCount); | 
 | 1241 |                 return NO_ERROR; | 
 | 1242 |             } | 
 | 1243 |         } | 
 | 1244 |     } | 
 | 1245 | } | 
 | 1246 |  | 
 | 1247 | // Yield samples from the timed buffer queue head up to the given output | 
 | 1248 | // buffer's capacity. | 
 | 1249 | // | 
 | 1250 | // Caller must hold mTimedBufferQueueLock | 
 | 1251 | void AudioFlinger::PlaybackThread::TimedTrack::timedYieldSamples_l( | 
 | 1252 |     AudioBufferProvider::Buffer* buffer) { | 
 | 1253 |  | 
 | 1254 |     const TimedBuffer& head = mTimedBufferQueue[0]; | 
 | 1255 |  | 
 | 1256 |     buffer->raw = (static_cast<uint8_t*>(head.buffer()->pointer()) + | 
 | 1257 |                    head.position()); | 
 | 1258 |  | 
 | 1259 |     uint32_t framesLeftInHead = ((head.buffer()->size() - head.position()) / | 
 | 1260 |                                  mFrameSize); | 
 | 1261 |     size_t framesRequested = buffer->frameCount; | 
 | 1262 |     buffer->frameCount = min(framesLeftInHead, framesRequested); | 
 | 1263 |  | 
 | 1264 |     mQueueHeadInFlight = true; | 
 | 1265 |     mTimedAudioOutputOnTime = true; | 
 | 1266 | } | 
 | 1267 |  | 
 | 1268 | // Yield samples of silence up to the given output buffer's capacity | 
 | 1269 | // | 
 | 1270 | // Caller must hold mTimedBufferQueueLock | 
 | 1271 | void AudioFlinger::PlaybackThread::TimedTrack::timedYieldSilence_l( | 
 | 1272 |     uint32_t numFrames, AudioBufferProvider::Buffer* buffer) { | 
 | 1273 |  | 
 | 1274 |     // lazily allocate a buffer filled with silence | 
 | 1275 |     if (mTimedSilenceBufferSize < numFrames * mFrameSize) { | 
 | 1276 |         delete [] mTimedSilenceBuffer; | 
 | 1277 |         mTimedSilenceBufferSize = numFrames * mFrameSize; | 
 | 1278 |         mTimedSilenceBuffer = new uint8_t[mTimedSilenceBufferSize]; | 
 | 1279 |         memset(mTimedSilenceBuffer, 0, mTimedSilenceBufferSize); | 
 | 1280 |     } | 
 | 1281 |  | 
 | 1282 |     buffer->raw = mTimedSilenceBuffer; | 
 | 1283 |     size_t framesRequested = buffer->frameCount; | 
 | 1284 |     buffer->frameCount = min(numFrames, framesRequested); | 
 | 1285 |  | 
 | 1286 |     mTimedAudioOutputOnTime = false; | 
 | 1287 | } | 
 | 1288 |  | 
 | 1289 | // AudioBufferProvider interface | 
 | 1290 | void AudioFlinger::PlaybackThread::TimedTrack::releaseBuffer( | 
 | 1291 |     AudioBufferProvider::Buffer* buffer) { | 
 | 1292 |  | 
 | 1293 |     Mutex::Autolock _l(mTimedBufferQueueLock); | 
 | 1294 |  | 
 | 1295 |     // If the buffer which was just released is part of the buffer at the head | 
 | 1296 |     // of the queue, be sure to update the amt of the buffer which has been | 
 | 1297 |     // consumed.  If the buffer being returned is not part of the head of the | 
 | 1298 |     // queue, its either because the buffer is part of the silence buffer, or | 
 | 1299 |     // because the head of the timed queue was trimmed after the mixer called | 
 | 1300 |     // getNextBuffer but before the mixer called releaseBuffer. | 
 | 1301 |     if (buffer->raw == mTimedSilenceBuffer) { | 
 | 1302 |         ALOG_ASSERT(!mQueueHeadInFlight, | 
 | 1303 |                     "Queue head in flight during release of silence buffer!"); | 
 | 1304 |         goto done; | 
 | 1305 |     } | 
 | 1306 |  | 
 | 1307 |     ALOG_ASSERT(mQueueHeadInFlight, | 
 | 1308 |                 "TimedTrack::releaseBuffer of non-silence buffer, but no queue" | 
 | 1309 |                 " head in flight."); | 
 | 1310 |  | 
 | 1311 |     if (mTimedBufferQueue.size()) { | 
 | 1312 |         TimedBuffer& head = mTimedBufferQueue.editItemAt(0); | 
 | 1313 |  | 
 | 1314 |         void* start = head.buffer()->pointer(); | 
 | 1315 |         void* end   = reinterpret_cast<void*>( | 
 | 1316 |                         reinterpret_cast<uint8_t*>(head.buffer()->pointer()) | 
 | 1317 |                         + head.buffer()->size()); | 
 | 1318 |  | 
 | 1319 |         ALOG_ASSERT((buffer->raw >= start) && (buffer->raw < end), | 
 | 1320 |                     "released buffer not within the head of the timed buffer" | 
 | 1321 |                     " queue; qHead = [%p, %p], released buffer = %p", | 
 | 1322 |                     start, end, buffer->raw); | 
 | 1323 |  | 
 | 1324 |         head.setPosition(head.position() + | 
 | 1325 |                 (buffer->frameCount * mFrameSize)); | 
 | 1326 |         mQueueHeadInFlight = false; | 
 | 1327 |  | 
 | 1328 |         ALOG_ASSERT(mFramesPendingInQueue >= buffer->frameCount, | 
 | 1329 |                     "Bad bookkeeping during releaseBuffer!  Should have at" | 
 | 1330 |                     " least %u queued frames, but we think we have only %u", | 
 | 1331 |                     buffer->frameCount, mFramesPendingInQueue); | 
 | 1332 |  | 
 | 1333 |         mFramesPendingInQueue -= buffer->frameCount; | 
 | 1334 |  | 
 | 1335 |         if ((static_cast<size_t>(head.position()) >= head.buffer()->size()) | 
 | 1336 |             || mTrimQueueHeadOnRelease) { | 
 | 1337 |             trimTimedBufferQueueHead_l("releaseBuffer"); | 
 | 1338 |             mTrimQueueHeadOnRelease = false; | 
 | 1339 |         } | 
 | 1340 |     } else { | 
 | 1341 |         LOG_FATAL("TimedTrack::releaseBuffer of non-silence buffer with no" | 
 | 1342 |                   " buffers in the timed buffer queue"); | 
 | 1343 |     } | 
 | 1344 |  | 
 | 1345 | done: | 
 | 1346 |     buffer->raw = 0; | 
 | 1347 |     buffer->frameCount = 0; | 
 | 1348 | } | 
 | 1349 |  | 
 | 1350 | size_t AudioFlinger::PlaybackThread::TimedTrack::framesReady() const { | 
 | 1351 |     Mutex::Autolock _l(mTimedBufferQueueLock); | 
 | 1352 |     return mFramesPendingInQueue; | 
 | 1353 | } | 
 | 1354 |  | 
 | 1355 | AudioFlinger::PlaybackThread::TimedTrack::TimedBuffer::TimedBuffer() | 
 | 1356 |         : mPTS(0), mPosition(0) {} | 
 | 1357 |  | 
 | 1358 | AudioFlinger::PlaybackThread::TimedTrack::TimedBuffer::TimedBuffer( | 
 | 1359 |     const sp<IMemory>& buffer, int64_t pts) | 
 | 1360 |         : mBuffer(buffer), mPTS(pts), mPosition(0) {} | 
 | 1361 |  | 
 | 1362 |  | 
 | 1363 | // ---------------------------------------------------------------------------- | 
 | 1364 |  | 
 | 1365 | AudioFlinger::PlaybackThread::OutputTrack::OutputTrack( | 
 | 1366 |             PlaybackThread *playbackThread, | 
 | 1367 |             DuplicatingThread *sourceThread, | 
 | 1368 |             uint32_t sampleRate, | 
 | 1369 |             audio_format_t format, | 
 | 1370 |             audio_channel_mask_t channelMask, | 
 | 1371 |             size_t frameCount) | 
 | 1372 |     :   Track(playbackThread, NULL, AUDIO_STREAM_CNT, sampleRate, format, channelMask, frameCount, | 
 | 1373 |                 NULL, 0, IAudioFlinger::TRACK_DEFAULT), | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 1374 |     mActive(false), mSourceThread(sourceThread), mClientProxy(NULL) | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 1375 | { | 
 | 1376 |  | 
 | 1377 |     if (mCblk != NULL) { | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 1378 |         mOutBuffer.frameCount = 0; | 
 | 1379 |         playbackThread->mTracks.add(this); | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 1380 |         ALOGV("OutputTrack constructor mCblk %p, mBuffer %p, " | 
 | 1381 |                 "mCblk->frameCount_ %u, mChannelMask 0x%08x mBufferEnd %p", | 
 | 1382 |                 mCblk, mBuffer, | 
 | 1383 |                 mCblk->frameCount_, mChannelMask, mBufferEnd); | 
 | 1384 |         // since client and server are in the same process, | 
 | 1385 |         // the buffer has the same virtual address on both sides | 
 | 1386 |         mClientProxy = new AudioTrackClientProxy(mCblk, mBuffer, mFrameCount, mFrameSize); | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 1387 |     } else { | 
 | 1388 |         ALOGW("Error creating output track on thread %p", playbackThread); | 
 | 1389 |     } | 
 | 1390 | } | 
 | 1391 |  | 
 | 1392 | AudioFlinger::PlaybackThread::OutputTrack::~OutputTrack() | 
 | 1393 | { | 
 | 1394 |     clearBufferQueue(); | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 1395 |     delete mClientProxy; | 
 | 1396 |     // superclass destructor will now delete the server proxy and shared memory both refer to | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 1397 | } | 
 | 1398 |  | 
 | 1399 | status_t AudioFlinger::PlaybackThread::OutputTrack::start(AudioSystem::sync_event_t event, | 
 | 1400 |                                                           int triggerSession) | 
 | 1401 | { | 
 | 1402 |     status_t status = Track::start(event, triggerSession); | 
 | 1403 |     if (status != NO_ERROR) { | 
 | 1404 |         return status; | 
 | 1405 |     } | 
 | 1406 |  | 
 | 1407 |     mActive = true; | 
 | 1408 |     mRetryCount = 127; | 
 | 1409 |     return status; | 
 | 1410 | } | 
 | 1411 |  | 
 | 1412 | void AudioFlinger::PlaybackThread::OutputTrack::stop() | 
 | 1413 | { | 
 | 1414 |     Track::stop(); | 
 | 1415 |     clearBufferQueue(); | 
 | 1416 |     mOutBuffer.frameCount = 0; | 
 | 1417 |     mActive = false; | 
 | 1418 | } | 
 | 1419 |  | 
 | 1420 | bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t frames) | 
 | 1421 | { | 
 | 1422 |     Buffer *pInBuffer; | 
 | 1423 |     Buffer inBuffer; | 
 | 1424 |     uint32_t channelCount = mChannelCount; | 
 | 1425 |     bool outputBufferFull = false; | 
 | 1426 |     inBuffer.frameCount = frames; | 
 | 1427 |     inBuffer.i16 = data; | 
 | 1428 |  | 
 | 1429 |     uint32_t waitTimeLeftMs = mSourceThread->waitTimeMs(); | 
 | 1430 |  | 
 | 1431 |     if (!mActive && frames != 0) { | 
 | 1432 |         start(); | 
 | 1433 |         sp<ThreadBase> thread = mThread.promote(); | 
 | 1434 |         if (thread != 0) { | 
 | 1435 |             MixerThread *mixerThread = (MixerThread *)thread.get(); | 
 | 1436 |             if (mFrameCount > frames) { | 
 | 1437 |                 if (mBufferQueue.size() < kMaxOverFlowBuffers) { | 
 | 1438 |                     uint32_t startFrames = (mFrameCount - frames); | 
 | 1439 |                     pInBuffer = new Buffer; | 
 | 1440 |                     pInBuffer->mBuffer = new int16_t[startFrames * channelCount]; | 
 | 1441 |                     pInBuffer->frameCount = startFrames; | 
 | 1442 |                     pInBuffer->i16 = pInBuffer->mBuffer; | 
 | 1443 |                     memset(pInBuffer->raw, 0, startFrames * channelCount * sizeof(int16_t)); | 
 | 1444 |                     mBufferQueue.add(pInBuffer); | 
 | 1445 |                 } else { | 
 | 1446 |                     ALOGW ("OutputTrack::write() %p no more buffers in queue", this); | 
 | 1447 |                 } | 
 | 1448 |             } | 
 | 1449 |         } | 
 | 1450 |     } | 
 | 1451 |  | 
 | 1452 |     while (waitTimeLeftMs) { | 
 | 1453 |         // First write pending buffers, then new data | 
 | 1454 |         if (mBufferQueue.size()) { | 
 | 1455 |             pInBuffer = mBufferQueue.itemAt(0); | 
 | 1456 |         } else { | 
 | 1457 |             pInBuffer = &inBuffer; | 
 | 1458 |         } | 
 | 1459 |  | 
 | 1460 |         if (pInBuffer->frameCount == 0) { | 
 | 1461 |             break; | 
 | 1462 |         } | 
 | 1463 |  | 
 | 1464 |         if (mOutBuffer.frameCount == 0) { | 
 | 1465 |             mOutBuffer.frameCount = pInBuffer->frameCount; | 
 | 1466 |             nsecs_t startTime = systemTime(); | 
 | 1467 |             if (obtainBuffer(&mOutBuffer, waitTimeLeftMs) == (status_t)NO_MORE_BUFFERS) { | 
 | 1468 |                 ALOGV ("OutputTrack::write() %p thread %p no more output buffers", this, | 
 | 1469 |                         mThread.unsafe_get()); | 
 | 1470 |                 outputBufferFull = true; | 
 | 1471 |                 break; | 
 | 1472 |             } | 
 | 1473 |             uint32_t waitTimeMs = (uint32_t)ns2ms(systemTime() - startTime); | 
 | 1474 |             if (waitTimeLeftMs >= waitTimeMs) { | 
 | 1475 |                 waitTimeLeftMs -= waitTimeMs; | 
 | 1476 |             } else { | 
 | 1477 |                 waitTimeLeftMs = 0; | 
 | 1478 |             } | 
 | 1479 |         } | 
 | 1480 |  | 
 | 1481 |         uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount : | 
 | 1482 |                 pInBuffer->frameCount; | 
 | 1483 |         memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channelCount * sizeof(int16_t)); | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 1484 |         mClientProxy->stepUser(outFrames); | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 1485 |         pInBuffer->frameCount -= outFrames; | 
 | 1486 |         pInBuffer->i16 += outFrames * channelCount; | 
 | 1487 |         mOutBuffer.frameCount -= outFrames; | 
 | 1488 |         mOutBuffer.i16 += outFrames * channelCount; | 
 | 1489 |  | 
 | 1490 |         if (pInBuffer->frameCount == 0) { | 
 | 1491 |             if (mBufferQueue.size()) { | 
 | 1492 |                 mBufferQueue.removeAt(0); | 
 | 1493 |                 delete [] pInBuffer->mBuffer; | 
 | 1494 |                 delete pInBuffer; | 
 | 1495 |                 ALOGV("OutputTrack::write() %p thread %p released overflow buffer %d", this, | 
 | 1496 |                         mThread.unsafe_get(), mBufferQueue.size()); | 
 | 1497 |             } else { | 
 | 1498 |                 break; | 
 | 1499 |             } | 
 | 1500 |         } | 
 | 1501 |     } | 
 | 1502 |  | 
 | 1503 |     // If we could not write all frames, allocate a buffer and queue it for next time. | 
 | 1504 |     if (inBuffer.frameCount) { | 
 | 1505 |         sp<ThreadBase> thread = mThread.promote(); | 
 | 1506 |         if (thread != 0 && !thread->standby()) { | 
 | 1507 |             if (mBufferQueue.size() < kMaxOverFlowBuffers) { | 
 | 1508 |                 pInBuffer = new Buffer; | 
 | 1509 |                 pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channelCount]; | 
 | 1510 |                 pInBuffer->frameCount = inBuffer.frameCount; | 
 | 1511 |                 pInBuffer->i16 = pInBuffer->mBuffer; | 
 | 1512 |                 memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channelCount * | 
 | 1513 |                         sizeof(int16_t)); | 
 | 1514 |                 mBufferQueue.add(pInBuffer); | 
 | 1515 |                 ALOGV("OutputTrack::write() %p thread %p adding overflow buffer %d", this, | 
 | 1516 |                         mThread.unsafe_get(), mBufferQueue.size()); | 
 | 1517 |             } else { | 
 | 1518 |                 ALOGW("OutputTrack::write() %p thread %p no more overflow buffers", | 
 | 1519 |                         mThread.unsafe_get(), this); | 
 | 1520 |             } | 
 | 1521 |         } | 
 | 1522 |     } | 
 | 1523 |  | 
 | 1524 |     // Calling write() with a 0 length buffer, means that no more data will be written: | 
 | 1525 |     // If no more buffers are pending, fill output track buffer to make sure it is started | 
 | 1526 |     // by output mixer. | 
 | 1527 |     if (frames == 0 && mBufferQueue.size() == 0) { | 
 | 1528 |         if (mCblk->user < mFrameCount) { | 
 | 1529 |             frames = mFrameCount - mCblk->user; | 
 | 1530 |             pInBuffer = new Buffer; | 
 | 1531 |             pInBuffer->mBuffer = new int16_t[frames * channelCount]; | 
 | 1532 |             pInBuffer->frameCount = frames; | 
 | 1533 |             pInBuffer->i16 = pInBuffer->mBuffer; | 
 | 1534 |             memset(pInBuffer->raw, 0, frames * channelCount * sizeof(int16_t)); | 
 | 1535 |             mBufferQueue.add(pInBuffer); | 
 | 1536 |         } else if (mActive) { | 
 | 1537 |             stop(); | 
 | 1538 |         } | 
 | 1539 |     } | 
 | 1540 |  | 
 | 1541 |     return outputBufferFull; | 
 | 1542 | } | 
 | 1543 |  | 
 | 1544 | status_t AudioFlinger::PlaybackThread::OutputTrack::obtainBuffer( | 
 | 1545 |         AudioBufferProvider::Buffer* buffer, uint32_t waitTimeMs) | 
 | 1546 | { | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 1547 |     audio_track_cblk_t* cblk = mCblk; | 
 | 1548 |     uint32_t framesReq = buffer->frameCount; | 
 | 1549 |  | 
 | 1550 |     ALOGVV("OutputTrack::obtainBuffer user %d, server %d", cblk->user, cblk->server); | 
 | 1551 |     buffer->frameCount  = 0; | 
 | 1552 |  | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 1553 |     size_t framesAvail; | 
 | 1554 |     { | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 1555 |         Mutex::Autolock _l(cblk->lock); | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 1556 |  | 
 | 1557 |         // read the server count again | 
 | 1558 |         while (!(framesAvail = mClientProxy->framesAvailable_l())) { | 
 | 1559 |             if (CC_UNLIKELY(!mActive)) { | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 1560 |                 ALOGV("Not active and NO_MORE_BUFFERS"); | 
 | 1561 |                 return NO_MORE_BUFFERS; | 
 | 1562 |             } | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 1563 |             status_t result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs)); | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 1564 |             if (result != NO_ERROR) { | 
 | 1565 |                 return NO_MORE_BUFFERS; | 
 | 1566 |             } | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 1567 |         } | 
 | 1568 |     } | 
 | 1569 |  | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 1570 |     if (framesReq > framesAvail) { | 
 | 1571 |         framesReq = framesAvail; | 
 | 1572 |     } | 
 | 1573 |  | 
 | 1574 |     uint32_t u = cblk->user; | 
 | 1575 |     uint32_t bufferEnd = cblk->userBase + mFrameCount; | 
 | 1576 |  | 
 | 1577 |     if (framesReq > bufferEnd - u) { | 
 | 1578 |         framesReq = bufferEnd - u; | 
 | 1579 |     } | 
 | 1580 |  | 
 | 1581 |     buffer->frameCount  = framesReq; | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 1582 |     buffer->raw         = mClientProxy->buffer(u); | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 1583 |     return NO_ERROR; | 
 | 1584 | } | 
 | 1585 |  | 
 | 1586 |  | 
 | 1587 | void AudioFlinger::PlaybackThread::OutputTrack::clearBufferQueue() | 
 | 1588 | { | 
 | 1589 |     size_t size = mBufferQueue.size(); | 
 | 1590 |  | 
 | 1591 |     for (size_t i = 0; i < size; i++) { | 
 | 1592 |         Buffer *pBuffer = mBufferQueue.itemAt(i); | 
 | 1593 |         delete [] pBuffer->mBuffer; | 
 | 1594 |         delete pBuffer; | 
 | 1595 |     } | 
 | 1596 |     mBufferQueue.clear(); | 
 | 1597 | } | 
 | 1598 |  | 
 | 1599 |  | 
 | 1600 | // ---------------------------------------------------------------------------- | 
 | 1601 | //      Record | 
 | 1602 | // ---------------------------------------------------------------------------- | 
 | 1603 |  | 
 | 1604 | AudioFlinger::RecordHandle::RecordHandle( | 
 | 1605 |         const sp<AudioFlinger::RecordThread::RecordTrack>& recordTrack) | 
 | 1606 |     : BnAudioRecord(), | 
 | 1607 |     mRecordTrack(recordTrack) | 
 | 1608 | { | 
 | 1609 | } | 
 | 1610 |  | 
 | 1611 | AudioFlinger::RecordHandle::~RecordHandle() { | 
 | 1612 |     stop_nonvirtual(); | 
 | 1613 |     mRecordTrack->destroy(); | 
 | 1614 | } | 
 | 1615 |  | 
 | 1616 | sp<IMemory> AudioFlinger::RecordHandle::getCblk() const { | 
 | 1617 |     return mRecordTrack->getCblk(); | 
 | 1618 | } | 
 | 1619 |  | 
 | 1620 | status_t AudioFlinger::RecordHandle::start(int /*AudioSystem::sync_event_t*/ event, | 
 | 1621 |         int triggerSession) { | 
 | 1622 |     ALOGV("RecordHandle::start()"); | 
 | 1623 |     return mRecordTrack->start((AudioSystem::sync_event_t)event, triggerSession); | 
 | 1624 | } | 
 | 1625 |  | 
 | 1626 | void AudioFlinger::RecordHandle::stop() { | 
 | 1627 |     stop_nonvirtual(); | 
 | 1628 | } | 
 | 1629 |  | 
 | 1630 | void AudioFlinger::RecordHandle::stop_nonvirtual() { | 
 | 1631 |     ALOGV("RecordHandle::stop()"); | 
 | 1632 |     mRecordTrack->stop(); | 
 | 1633 | } | 
 | 1634 |  | 
 | 1635 | status_t AudioFlinger::RecordHandle::onTransact( | 
 | 1636 |     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) | 
 | 1637 | { | 
 | 1638 |     return BnAudioRecord::onTransact(code, data, reply, flags); | 
 | 1639 | } | 
 | 1640 |  | 
 | 1641 | // ---------------------------------------------------------------------------- | 
 | 1642 |  | 
 | 1643 | // RecordTrack constructor must be called with AudioFlinger::mLock held | 
 | 1644 | AudioFlinger::RecordThread::RecordTrack::RecordTrack( | 
 | 1645 |             RecordThread *thread, | 
 | 1646 |             const sp<Client>& client, | 
 | 1647 |             uint32_t sampleRate, | 
 | 1648 |             audio_format_t format, | 
 | 1649 |             audio_channel_mask_t channelMask, | 
 | 1650 |             size_t frameCount, | 
 | 1651 |             int sessionId) | 
 | 1652 |     :   TrackBase(thread, client, sampleRate, format, | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 1653 |                   channelMask, frameCount, 0 /*sharedBuffer*/, sessionId, false /*isOut*/), | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 1654 |         mOverflow(false) | 
 | 1655 | { | 
 | 1656 |     ALOGV("RecordTrack constructor, size %d", (int)mBufferEnd - (int)mBuffer); | 
 | 1657 | } | 
 | 1658 |  | 
 | 1659 | AudioFlinger::RecordThread::RecordTrack::~RecordTrack() | 
 | 1660 | { | 
 | 1661 |     ALOGV("%s", __func__); | 
 | 1662 | } | 
 | 1663 |  | 
 | 1664 | // AudioBufferProvider interface | 
 | 1665 | status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer, | 
 | 1666 |         int64_t pts) | 
 | 1667 | { | 
 | 1668 |     audio_track_cblk_t* cblk = this->cblk(); | 
 | 1669 |     uint32_t framesAvail; | 
 | 1670 |     uint32_t framesReq = buffer->frameCount; | 
 | 1671 |  | 
 | 1672 |     // Check if last stepServer failed, try to step now | 
 | 1673 |     if (mStepServerFailed) { | 
 | 1674 |         if (!step()) { | 
 | 1675 |             goto getNextBuffer_exit; | 
 | 1676 |         } | 
 | 1677 |         ALOGV("stepServer recovered"); | 
 | 1678 |         mStepServerFailed = false; | 
 | 1679 |     } | 
 | 1680 |  | 
 | 1681 |     // FIXME lock is not actually held, so overrun is possible | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 1682 |     framesAvail = mServerProxy->framesAvailableIn_l(); | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 1683 |  | 
 | 1684 |     if (CC_LIKELY(framesAvail)) { | 
 | 1685 |         uint32_t s = cblk->server; | 
 | 1686 |         uint32_t bufferEnd = cblk->serverBase + mFrameCount; | 
 | 1687 |  | 
 | 1688 |         if (framesReq > framesAvail) { | 
 | 1689 |             framesReq = framesAvail; | 
 | 1690 |         } | 
 | 1691 |         if (framesReq > bufferEnd - s) { | 
 | 1692 |             framesReq = bufferEnd - s; | 
 | 1693 |         } | 
 | 1694 |  | 
 | 1695 |         buffer->raw = getBuffer(s, framesReq); | 
 | 1696 |         buffer->frameCount = framesReq; | 
 | 1697 |         return NO_ERROR; | 
 | 1698 |     } | 
 | 1699 |  | 
 | 1700 | getNextBuffer_exit: | 
 | 1701 |     buffer->raw = NULL; | 
 | 1702 |     buffer->frameCount = 0; | 
 | 1703 |     return NOT_ENOUGH_DATA; | 
 | 1704 | } | 
 | 1705 |  | 
 | 1706 | status_t AudioFlinger::RecordThread::RecordTrack::start(AudioSystem::sync_event_t event, | 
 | 1707 |                                                         int triggerSession) | 
 | 1708 | { | 
 | 1709 |     sp<ThreadBase> thread = mThread.promote(); | 
 | 1710 |     if (thread != 0) { | 
 | 1711 |         RecordThread *recordThread = (RecordThread *)thread.get(); | 
 | 1712 |         return recordThread->start(this, event, triggerSession); | 
 | 1713 |     } else { | 
 | 1714 |         return BAD_VALUE; | 
 | 1715 |     } | 
 | 1716 | } | 
 | 1717 |  | 
 | 1718 | void AudioFlinger::RecordThread::RecordTrack::stop() | 
 | 1719 | { | 
 | 1720 |     sp<ThreadBase> thread = mThread.promote(); | 
 | 1721 |     if (thread != 0) { | 
 | 1722 |         RecordThread *recordThread = (RecordThread *)thread.get(); | 
 | 1723 |         recordThread->mLock.lock(); | 
 | 1724 |         bool doStop = recordThread->stop_l(this); | 
 | 1725 |         if (doStop) { | 
 | 1726 |             TrackBase::reset(); | 
 | 1727 |             // Force overrun condition to avoid false overrun callback until first data is | 
 | 1728 |             // read from buffer | 
 | 1729 |             android_atomic_or(CBLK_UNDERRUN, &mCblk->flags); | 
 | 1730 |         } | 
 | 1731 |         recordThread->mLock.unlock(); | 
 | 1732 |         if (doStop) { | 
 | 1733 |             AudioSystem::stopInput(recordThread->id()); | 
 | 1734 |         } | 
 | 1735 |     } | 
 | 1736 | } | 
 | 1737 |  | 
 | 1738 | void AudioFlinger::RecordThread::RecordTrack::destroy() | 
 | 1739 | { | 
 | 1740 |     // see comments at AudioFlinger::PlaybackThread::Track::destroy() | 
 | 1741 |     sp<RecordTrack> keep(this); | 
 | 1742 |     { | 
 | 1743 |         sp<ThreadBase> thread = mThread.promote(); | 
 | 1744 |         if (thread != 0) { | 
 | 1745 |             if (mState == ACTIVE || mState == RESUMING) { | 
 | 1746 |                 AudioSystem::stopInput(thread->id()); | 
 | 1747 |             } | 
 | 1748 |             AudioSystem::releaseInput(thread->id()); | 
 | 1749 |             Mutex::Autolock _l(thread->mLock); | 
 | 1750 |             RecordThread *recordThread = (RecordThread *) thread.get(); | 
 | 1751 |             recordThread->destroyTrack_l(this); | 
 | 1752 |         } | 
 | 1753 |     } | 
 | 1754 | } | 
 | 1755 |  | 
 | 1756 |  | 
 | 1757 | /*static*/ void AudioFlinger::RecordThread::RecordTrack::appendDumpHeader(String8& result) | 
 | 1758 | { | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 1759 |     result.append("   Clien Fmt Chn mask   Session Step S Serv     User   FrameCount\n"); | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 1760 | } | 
 | 1761 |  | 
 | 1762 | void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size) | 
 | 1763 | { | 
| Glenn Kasten | e3aa659 | 2012-12-04 12:22:46 -0800 | [diff] [blame] | 1764 |     snprintf(buffer, size, "   %05d %03u 0x%08x %05d   %04u %01d %08x %08x %05d\n", | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 1765 |             (mClient == 0) ? getpid_cached : mClient->pid(), | 
 | 1766 |             mFormat, | 
 | 1767 |             mChannelMask, | 
 | 1768 |             mSessionId, | 
 | 1769 |             mStepCount, | 
 | 1770 |             mState, | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 1771 |             mCblk->server, | 
 | 1772 |             mCblk->user, | 
 | 1773 |             mFrameCount); | 
 | 1774 | } | 
 | 1775 |  | 
| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame] | 1776 | }; // namespace android |