Tracks.cpp revision 30d48d9542fb3f85889108c1ee2daff98a4860e7
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 "Configuration.h" 23#include <linux/futex.h> 24#include <math.h> 25#include <sys/syscall.h> 26#include <utils/Log.h> 27 28#include <private/media/AudioTrackShared.h> 29 30#include "AudioFlinger.h" 31#include "ServiceUtilities.h" 32 33#include <media/nbaio/Pipe.h> 34#include <media/nbaio/PipeReader.h> 35#include <media/RecordBufferConverter.h> 36#include <audio_utils/minifloat.h> 37 38// ---------------------------------------------------------------------------- 39 40// Note: the following macro is used for extremely verbose logging message. In 41// order to run with ALOG_ASSERT turned on, we need to have LOG_NDEBUG set to 42// 0; but one side effect of this is to turn all LOGV's as well. Some messages 43// are so verbose that we want to suppress them even when we have ALOG_ASSERT 44// turned on. Do not uncomment the #def below unless you really know what you 45// are doing and want to see all of the extremely verbose messages. 46//#define VERY_VERY_VERBOSE_LOGGING 47#ifdef VERY_VERY_VERBOSE_LOGGING 48#define ALOGVV ALOGV 49#else 50#define ALOGVV(a...) do { } while(0) 51#endif 52 53// TODO move to a common header (Also shared with AudioTrack.cpp) 54#define NANOS_PER_SECOND 1000000000 55#define TIME_TO_NANOS(time) ((uint64_t)(time).tv_sec * NANOS_PER_SECOND + (time).tv_nsec) 56 57namespace android { 58 59// ---------------------------------------------------------------------------- 60// TrackBase 61// ---------------------------------------------------------------------------- 62 63static volatile int32_t nextTrackId = 55; 64 65// TrackBase constructor must be called with AudioFlinger::mLock held 66AudioFlinger::ThreadBase::TrackBase::TrackBase( 67 ThreadBase *thread, 68 const sp<Client>& client, 69 uint32_t sampleRate, 70 audio_format_t format, 71 audio_channel_mask_t channelMask, 72 size_t frameCount, 73 void *buffer, 74 audio_session_t sessionId, 75 uid_t clientUid, 76 bool isOut, 77 alloc_type alloc, 78 track_type type, 79 audio_port_handle_t portId) 80 : RefBase(), 81 mThread(thread), 82 mClient(client), 83 mCblk(NULL), 84 // mBuffer 85 mState(IDLE), 86 mSampleRate(sampleRate), 87 mFormat(format), 88 mChannelMask(channelMask), 89 mChannelCount(isOut ? 90 audio_channel_count_from_out_mask(channelMask) : 91 audio_channel_count_from_in_mask(channelMask)), 92 mFrameSize(audio_has_proportional_frames(format) ? 93 mChannelCount * audio_bytes_per_sample(format) : sizeof(int8_t)), 94 mFrameCount(frameCount), 95 mSessionId(sessionId), 96 mIsOut(isOut), 97 mId(android_atomic_inc(&nextTrackId)), 98 mTerminated(false), 99 mType(type), 100 mThreadIoHandle(thread->id()), 101 mPortId(portId), 102 mIsInvalid(false) 103{ 104 const uid_t callingUid = IPCThreadState::self()->getCallingUid(); 105 if (!isTrustedCallingUid(callingUid) || clientUid == AUDIO_UID_INVALID) { 106 ALOGW_IF(clientUid != AUDIO_UID_INVALID && clientUid != callingUid, 107 "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, clientUid); 108 clientUid = callingUid; 109 } 110 // clientUid contains the uid of the app that is responsible for this track, so we can blame 111 // battery usage on it. 112 mUid = clientUid; 113 114 // ALOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize); 115 size_t size = sizeof(audio_track_cblk_t); 116 size_t bufferSize = (buffer == NULL ? roundup(frameCount) : frameCount) * mFrameSize; 117 if (buffer == NULL && alloc == ALLOC_CBLK) { 118 size += bufferSize; 119 } 120 121 if (client != 0) { 122 mCblkMemory = client->heap()->allocate(size); 123 if (mCblkMemory == 0 || 124 (mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer())) == NULL) { 125 ALOGE("not enough memory for AudioTrack size=%zu", size); 126 client->heap()->dump("AudioTrack"); 127 mCblkMemory.clear(); 128 return; 129 } 130 } else { 131 // this syntax avoids calling the audio_track_cblk_t constructor twice 132 mCblk = (audio_track_cblk_t *) new uint8_t[size]; 133 // assume mCblk != NULL 134 } 135 136 // construct the shared structure in-place. 137 if (mCblk != NULL) { 138 new(mCblk) audio_track_cblk_t(); 139 switch (alloc) { 140 case ALLOC_READONLY: { 141 const sp<MemoryDealer> roHeap(thread->readOnlyHeap()); 142 if (roHeap == 0 || 143 (mBufferMemory = roHeap->allocate(bufferSize)) == 0 || 144 (mBuffer = mBufferMemory->pointer()) == NULL) { 145 ALOGE("not enough memory for read-only buffer size=%zu", bufferSize); 146 if (roHeap != 0) { 147 roHeap->dump("buffer"); 148 } 149 mCblkMemory.clear(); 150 mBufferMemory.clear(); 151 return; 152 } 153 memset(mBuffer, 0, bufferSize); 154 } break; 155 case ALLOC_PIPE: 156 mBufferMemory = thread->pipeMemory(); 157 // mBuffer is the virtual address as seen from current process (mediaserver), 158 // and should normally be coming from mBufferMemory->pointer(). 159 // However in this case the TrackBase does not reference the buffer directly. 160 // It should references the buffer via the pipe. 161 // Therefore, to detect incorrect usage of the buffer, we set mBuffer to NULL. 162 mBuffer = NULL; 163 break; 164 case ALLOC_CBLK: 165 // clear all buffers 166 if (buffer == NULL) { 167 mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t); 168 memset(mBuffer, 0, bufferSize); 169 } else { 170 mBuffer = buffer; 171#if 0 172 mCblk->mFlags = CBLK_FORCEREADY; // FIXME hack, need to fix the track ready logic 173#endif 174 } 175 break; 176 case ALLOC_LOCAL: 177 mBuffer = calloc(1, bufferSize); 178 break; 179 case ALLOC_NONE: 180 mBuffer = buffer; 181 break; 182 } 183 184#ifdef TEE_SINK 185 if (mTeeSinkTrackEnabled) { 186 NBAIO_Format pipeFormat = Format_from_SR_C(mSampleRate, mChannelCount, mFormat); 187 if (Format_isValid(pipeFormat)) { 188 Pipe *pipe = new Pipe(mTeeSinkTrackFrames, pipeFormat); 189 size_t numCounterOffers = 0; 190 const NBAIO_Format offers[1] = {pipeFormat}; 191 ssize_t index = pipe->negotiate(offers, 1, NULL, numCounterOffers); 192 ALOG_ASSERT(index == 0); 193 PipeReader *pipeReader = new PipeReader(*pipe); 194 numCounterOffers = 0; 195 index = pipeReader->negotiate(offers, 1, NULL, numCounterOffers); 196 ALOG_ASSERT(index == 0); 197 mTeeSink = pipe; 198 mTeeSource = pipeReader; 199 } 200 } 201#endif 202 203 } 204} 205 206status_t AudioFlinger::ThreadBase::TrackBase::initCheck() const 207{ 208 status_t status; 209 if (mType == TYPE_OUTPUT || mType == TYPE_PATCH) { 210 status = cblk() != NULL ? NO_ERROR : NO_MEMORY; 211 } else { 212 status = getCblk() != 0 ? NO_ERROR : NO_MEMORY; 213 } 214 return status; 215} 216 217AudioFlinger::ThreadBase::TrackBase::~TrackBase() 218{ 219#ifdef TEE_SINK 220 dumpTee(-1, mTeeSource, mId); 221#endif 222 // delete the proxy before deleting the shared memory it refers to, to avoid dangling reference 223 mServerProxy.clear(); 224 if (mCblk != NULL) { 225 if (mClient == 0) { 226 delete mCblk; 227 } else { 228 mCblk->~audio_track_cblk_t(); // destroy our shared-structure. 229 } 230 } 231 mCblkMemory.clear(); // free the shared memory before releasing the heap it belongs to 232 if (mClient != 0) { 233 // Client destructor must run with AudioFlinger client mutex locked 234 Mutex::Autolock _l(mClient->audioFlinger()->mClientLock); 235 // If the client's reference count drops to zero, the associated destructor 236 // must run with AudioFlinger lock held. Thus the explicit clear() rather than 237 // relying on the automatic clear() at end of scope. 238 mClient.clear(); 239 } 240 // flush the binder command buffer 241 IPCThreadState::self()->flushCommands(); 242} 243 244// AudioBufferProvider interface 245// getNextBuffer() = 0; 246// This implementation of releaseBuffer() is used by Track and RecordTrack 247void AudioFlinger::ThreadBase::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer) 248{ 249#ifdef TEE_SINK 250 if (mTeeSink != 0) { 251 (void) mTeeSink->write(buffer->raw, buffer->frameCount); 252 } 253#endif 254 255 ServerProxy::Buffer buf; 256 buf.mFrameCount = buffer->frameCount; 257 buf.mRaw = buffer->raw; 258 buffer->frameCount = 0; 259 buffer->raw = NULL; 260 mServerProxy->releaseBuffer(&buf); 261} 262 263status_t AudioFlinger::ThreadBase::TrackBase::setSyncEvent(const sp<SyncEvent>& event) 264{ 265 mSyncEvents.add(event); 266 return NO_ERROR; 267} 268 269// ---------------------------------------------------------------------------- 270// Playback 271// ---------------------------------------------------------------------------- 272 273AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::PlaybackThread::Track>& track) 274 : BnAudioTrack(), 275 mTrack(track) 276{ 277} 278 279AudioFlinger::TrackHandle::~TrackHandle() { 280 // just stop the track on deletion, associated resources 281 // will be freed from the main thread once all pending buffers have 282 // been played. Unless it's not in the active track list, in which 283 // case we free everything now... 284 mTrack->destroy(); 285} 286 287sp<IMemory> AudioFlinger::TrackHandle::getCblk() const { 288 return mTrack->getCblk(); 289} 290 291status_t AudioFlinger::TrackHandle::start() { 292 return mTrack->start(); 293} 294 295void AudioFlinger::TrackHandle::stop() { 296 mTrack->stop(); 297} 298 299void AudioFlinger::TrackHandle::flush() { 300 mTrack->flush(); 301} 302 303void AudioFlinger::TrackHandle::pause() { 304 mTrack->pause(); 305} 306 307status_t AudioFlinger::TrackHandle::attachAuxEffect(int EffectId) 308{ 309 return mTrack->attachAuxEffect(EffectId); 310} 311 312status_t AudioFlinger::TrackHandle::setParameters(const String8& keyValuePairs) { 313 return mTrack->setParameters(keyValuePairs); 314} 315 316VolumeShaper::Status AudioFlinger::TrackHandle::applyVolumeShaper( 317 const sp<VolumeShaper::Configuration>& configuration, 318 const sp<VolumeShaper::Operation>& operation) { 319 return mTrack->applyVolumeShaper(configuration, operation); 320} 321 322sp<VolumeShaper::State> AudioFlinger::TrackHandle::getVolumeShaperState(int id) { 323 return mTrack->getVolumeShaperState(id); 324} 325 326status_t AudioFlinger::TrackHandle::getTimestamp(AudioTimestamp& timestamp) 327{ 328 return mTrack->getTimestamp(timestamp); 329} 330 331 332void AudioFlinger::TrackHandle::signal() 333{ 334 return mTrack->signal(); 335} 336 337status_t AudioFlinger::TrackHandle::onTransact( 338 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) 339{ 340 return BnAudioTrack::onTransact(code, data, reply, flags); 341} 342 343// ---------------------------------------------------------------------------- 344 345// Track constructor must be called with AudioFlinger::mLock and ThreadBase::mLock held 346AudioFlinger::PlaybackThread::Track::Track( 347 PlaybackThread *thread, 348 const sp<Client>& client, 349 audio_stream_type_t streamType, 350 uint32_t sampleRate, 351 audio_format_t format, 352 audio_channel_mask_t channelMask, 353 size_t frameCount, 354 void *buffer, 355 const sp<IMemory>& sharedBuffer, 356 audio_session_t sessionId, 357 uid_t uid, 358 audio_output_flags_t flags, 359 track_type type, 360 audio_port_handle_t portId) 361 : TrackBase(thread, client, sampleRate, format, channelMask, frameCount, 362 (sharedBuffer != 0) ? sharedBuffer->pointer() : buffer, 363 sessionId, uid, true /*isOut*/, 364 (type == TYPE_PATCH) ? ( buffer == NULL ? ALLOC_LOCAL : ALLOC_NONE) : ALLOC_CBLK, 365 type, portId), 366 mFillingUpStatus(FS_INVALID), 367 // mRetryCount initialized later when needed 368 mSharedBuffer(sharedBuffer), 369 mStreamType(streamType), 370 mName(-1), // see note below 371 mMainBuffer(thread->mixBuffer()), 372 mAuxBuffer(NULL), 373 mAuxEffectId(0), mHasVolumeController(false), 374 mPresentationCompleteFrames(0), 375 mFrameMap(16 /* sink-frame-to-track-frame map memory */), 376 mVolumeHandler(new VolumeHandler(sampleRate)), 377 // mSinkTimestamp 378 mFastIndex(-1), 379 mCachedVolume(1.0), 380 mResumeToStopping(false), 381 mFlushHwPending(false), 382 mFlags(flags) 383{ 384 // client == 0 implies sharedBuffer == 0 385 ALOG_ASSERT(!(client == 0 && sharedBuffer != 0)); 386 387 ALOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %zu", sharedBuffer->pointer(), 388 sharedBuffer->size()); 389 390 if (mCblk == NULL) { 391 return; 392 } 393 394 if (sharedBuffer == 0) { 395 mAudioTrackServerProxy = new AudioTrackServerProxy(mCblk, mBuffer, frameCount, 396 mFrameSize, !isExternalTrack(), sampleRate); 397 } else { 398 mAudioTrackServerProxy = new StaticAudioTrackServerProxy(mCblk, mBuffer, frameCount, 399 mFrameSize); 400 } 401 mServerProxy = mAudioTrackServerProxy; 402 403 mName = thread->getTrackName_l(channelMask, format, sessionId, uid); 404 if (mName < 0) { 405 ALOGE("no more track names available"); 406 return; 407 } 408 // only allocate a fast track index if we were able to allocate a normal track name 409 if (flags & AUDIO_OUTPUT_FLAG_FAST) { 410 // FIXME: Not calling framesReadyIsCalledByMultipleThreads() exposes a potential 411 // race with setSyncEvent(). However, if we call it, we cannot properly start 412 // static fast tracks (SoundPool) immediately after stopping. 413 //mAudioTrackServerProxy->framesReadyIsCalledByMultipleThreads(); 414 ALOG_ASSERT(thread->mFastTrackAvailMask != 0); 415 int i = __builtin_ctz(thread->mFastTrackAvailMask); 416 ALOG_ASSERT(0 < i && i < (int)FastMixerState::sMaxFastTracks); 417 // FIXME This is too eager. We allocate a fast track index before the 418 // fast track becomes active. Since fast tracks are a scarce resource, 419 // this means we are potentially denying other more important fast tracks from 420 // being created. It would be better to allocate the index dynamically. 421 mFastIndex = i; 422 thread->mFastTrackAvailMask &= ~(1 << i); 423 } 424} 425 426AudioFlinger::PlaybackThread::Track::~Track() 427{ 428 ALOGV("PlaybackThread::Track destructor"); 429 430 // The destructor would clear mSharedBuffer, 431 // but it will not push the decremented reference count, 432 // leaving the client's IMemory dangling indefinitely. 433 // This prevents that leak. 434 if (mSharedBuffer != 0) { 435 mSharedBuffer.clear(); 436 } 437} 438 439status_t AudioFlinger::PlaybackThread::Track::initCheck() const 440{ 441 status_t status = TrackBase::initCheck(); 442 if (status == NO_ERROR && mName < 0) { 443 status = NO_MEMORY; 444 } 445 return status; 446} 447 448void AudioFlinger::PlaybackThread::Track::destroy() 449{ 450 // NOTE: destroyTrack_l() can remove a strong reference to this Track 451 // by removing it from mTracks vector, so there is a risk that this Tracks's 452 // destructor is called. As the destructor needs to lock mLock, 453 // we must acquire a strong reference on this Track before locking mLock 454 // here so that the destructor is called only when exiting this function. 455 // On the other hand, as long as Track::destroy() is only called by 456 // TrackHandle destructor, the TrackHandle still holds a strong ref on 457 // this Track with its member mTrack. 458 sp<Track> keep(this); 459 { // scope for mLock 460 bool wasActive = false; 461 sp<ThreadBase> thread = mThread.promote(); 462 if (thread != 0) { 463 Mutex::Autolock _l(thread->mLock); 464 PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); 465 wasActive = playbackThread->destroyTrack_l(this); 466 } 467 if (isExternalTrack() && !wasActive) { 468 AudioSystem::releaseOutput(mThreadIoHandle, mStreamType, mSessionId); 469 } 470 } 471} 472 473/*static*/ void AudioFlinger::PlaybackThread::Track::appendDumpHeader(String8& result) 474{ 475 result.append(" Name Active Client Type Fmt Chn mask Session fCount S F SRate " 476 "L dB R dB Server Main buf Aux buf Flags UndFrmCnt Flushed\n"); 477} 478 479void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size, bool active) 480{ 481 gain_minifloat_packed_t vlr = mAudioTrackServerProxy->getVolumeLR(); 482 if (isFastTrack()) { 483 sprintf(buffer, " F %2d", mFastIndex); 484 } else if (mName >= AudioMixer::TRACK0) { 485 sprintf(buffer, " %4d", mName - AudioMixer::TRACK0); 486 } else { 487 sprintf(buffer, " none"); 488 } 489 track_state state = mState; 490 char stateChar; 491 if (isTerminated()) { 492 stateChar = 'T'; 493 } else { 494 switch (state) { 495 case IDLE: 496 stateChar = 'I'; 497 break; 498 case STOPPING_1: 499 stateChar = 's'; 500 break; 501 case STOPPING_2: 502 stateChar = '5'; 503 break; 504 case STOPPED: 505 stateChar = 'S'; 506 break; 507 case RESUMING: 508 stateChar = 'R'; 509 break; 510 case ACTIVE: 511 stateChar = 'A'; 512 break; 513 case PAUSING: 514 stateChar = 'p'; 515 break; 516 case PAUSED: 517 stateChar = 'P'; 518 break; 519 case FLUSHED: 520 stateChar = 'F'; 521 break; 522 default: 523 stateChar = '?'; 524 break; 525 } 526 } 527 char nowInUnderrun; 528 switch (mObservedUnderruns.mBitFields.mMostRecent) { 529 case UNDERRUN_FULL: 530 nowInUnderrun = ' '; 531 break; 532 case UNDERRUN_PARTIAL: 533 nowInUnderrun = '<'; 534 break; 535 case UNDERRUN_EMPTY: 536 nowInUnderrun = '*'; 537 break; 538 default: 539 nowInUnderrun = '?'; 540 break; 541 } 542 snprintf(&buffer[8], size-8, " %6s %6u %4u %08X %08X %7u %6zu %1c %1d %5u %5.2g %5.2g " 543 "%08X %08zX %08zX 0x%03X %9u%c %7u\n", 544 active ? "yes" : "no", 545 (mClient == 0) ? getpid_cached : mClient->pid(), 546 mStreamType, 547 mFormat, 548 mChannelMask, 549 mSessionId, 550 mFrameCount, 551 stateChar, 552 mFillingUpStatus, 553 mAudioTrackServerProxy->getSampleRate(), 554 20.0 * log10(float_from_gain(gain_minifloat_unpack_left(vlr))), 555 20.0 * log10(float_from_gain(gain_minifloat_unpack_right(vlr))), 556 mCblk->mServer, 557 (size_t)mMainBuffer, // use %zX as %p appends 0x 558 (size_t)mAuxBuffer, // use %zX as %p appends 0x 559 mCblk->mFlags, 560 mAudioTrackServerProxy->getUnderrunFrames(), 561 nowInUnderrun, 562 (unsigned)mAudioTrackServerProxy->framesFlushed() % 10000000); // 7 digits 563} 564 565uint32_t AudioFlinger::PlaybackThread::Track::sampleRate() const { 566 return mAudioTrackServerProxy->getSampleRate(); 567} 568 569// AudioBufferProvider interface 570status_t AudioFlinger::PlaybackThread::Track::getNextBuffer( 571 AudioBufferProvider::Buffer* buffer) 572{ 573 ServerProxy::Buffer buf; 574 size_t desiredFrames = buffer->frameCount; 575 buf.mFrameCount = desiredFrames; 576 status_t status = mServerProxy->obtainBuffer(&buf); 577 buffer->frameCount = buf.mFrameCount; 578 buffer->raw = buf.mRaw; 579 if (buf.mFrameCount == 0) { 580 mAudioTrackServerProxy->tallyUnderrunFrames(desiredFrames); 581 } else { 582 mAudioTrackServerProxy->tallyUnderrunFrames(0); 583 } 584 585 return status; 586} 587 588// releaseBuffer() is not overridden 589 590// ExtendedAudioBufferProvider interface 591 592// framesReady() may return an approximation of the number of frames if called 593// from a different thread than the one calling Proxy->obtainBuffer() and 594// Proxy->releaseBuffer(). Also note there is no mutual exclusion in the 595// AudioTrackServerProxy so be especially careful calling with FastTracks. 596size_t AudioFlinger::PlaybackThread::Track::framesReady() const { 597 if (mSharedBuffer != 0 && (isStopped() || isStopping())) { 598 // Static tracks return zero frames immediately upon stopping (for FastTracks). 599 // The remainder of the buffer is not drained. 600 return 0; 601 } 602 return mAudioTrackServerProxy->framesReady(); 603} 604 605int64_t AudioFlinger::PlaybackThread::Track::framesReleased() const 606{ 607 return mAudioTrackServerProxy->framesReleased(); 608} 609 610void AudioFlinger::PlaybackThread::Track::onTimestamp(const ExtendedTimestamp ×tamp) 611{ 612 // This call comes from a FastTrack and should be kept lockless. 613 // The server side frames are already translated to client frames. 614 mAudioTrackServerProxy->setTimestamp(timestamp); 615 616 // We do not set drained here, as FastTrack timestamp may not go to very last frame. 617} 618 619// Don't call for fast tracks; the framesReady() could result in priority inversion 620bool AudioFlinger::PlaybackThread::Track::isReady() const { 621 if (mFillingUpStatus != FS_FILLING || isStopped() || isPausing()) { 622 return true; 623 } 624 625 if (isStopping()) { 626 if (framesReady() > 0) { 627 mFillingUpStatus = FS_FILLED; 628 } 629 return true; 630 } 631 632 if (framesReady() >= mServerProxy->getBufferSizeInFrames() || 633 (mCblk->mFlags & CBLK_FORCEREADY)) { 634 mFillingUpStatus = FS_FILLED; 635 android_atomic_and(~CBLK_FORCEREADY, &mCblk->mFlags); 636 return true; 637 } 638 return false; 639} 640 641status_t AudioFlinger::PlaybackThread::Track::start(AudioSystem::sync_event_t event __unused, 642 audio_session_t triggerSession __unused) 643{ 644 status_t status = NO_ERROR; 645 ALOGV("start(%d), calling pid %d session %d", 646 mName, IPCThreadState::self()->getCallingPid(), mSessionId); 647 648 sp<ThreadBase> thread = mThread.promote(); 649 if (thread != 0) { 650 if (isOffloaded()) { 651 Mutex::Autolock _laf(thread->mAudioFlinger->mLock); 652 Mutex::Autolock _lth(thread->mLock); 653 sp<EffectChain> ec = thread->getEffectChain_l(mSessionId); 654 if (thread->mAudioFlinger->isNonOffloadableGlobalEffectEnabled_l() || 655 (ec != 0 && ec->isNonOffloadableEnabled())) { 656 invalidate(); 657 return PERMISSION_DENIED; 658 } 659 } 660 Mutex::Autolock _lth(thread->mLock); 661 track_state state = mState; 662 // here the track could be either new, or restarted 663 // in both cases "unstop" the track 664 665 // initial state-stopping. next state-pausing. 666 // What if resume is called ? 667 668 if (state == PAUSED || state == PAUSING) { 669 if (mResumeToStopping) { 670 // happened we need to resume to STOPPING_1 671 mState = TrackBase::STOPPING_1; 672 ALOGV("PAUSED => STOPPING_1 (%d) on thread %p", mName, this); 673 } else { 674 mState = TrackBase::RESUMING; 675 ALOGV("PAUSED => RESUMING (%d) on thread %p", mName, this); 676 } 677 } else { 678 mState = TrackBase::ACTIVE; 679 ALOGV("? => ACTIVE (%d) on thread %p", mName, this); 680 } 681 682 // states to reset position info for non-offloaded/direct tracks 683 if (!isOffloaded() && !isDirect() 684 && (state == IDLE || state == STOPPED || state == FLUSHED)) { 685 mFrameMap.reset(); 686 } 687 PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); 688 if (isFastTrack()) { 689 // refresh fast track underruns on start because that field is never cleared 690 // by the fast mixer; furthermore, the same track can be recycled, i.e. start 691 // after stop. 692 mObservedUnderruns = playbackThread->getFastTrackUnderruns(mFastIndex); 693 } 694 status = playbackThread->addTrack_l(this); 695 if (status == INVALID_OPERATION || status == PERMISSION_DENIED) { 696 triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE); 697 // restore previous state if start was rejected by policy manager 698 if (status == PERMISSION_DENIED) { 699 mState = state; 700 } 701 } 702 // track was already in the active list, not a problem 703 if (status == ALREADY_EXISTS) { 704 status = NO_ERROR; 705 } else { 706 // Acknowledge any pending flush(), so that subsequent new data isn't discarded. 707 // It is usually unsafe to access the server proxy from a binder thread. 708 // But in this case we know the mixer thread (whether normal mixer or fast mixer) 709 // isn't looking at this track yet: we still hold the normal mixer thread lock, 710 // and for fast tracks the track is not yet in the fast mixer thread's active set. 711 // For static tracks, this is used to acknowledge change in position or loop. 712 ServerProxy::Buffer buffer; 713 buffer.mFrameCount = 1; 714 (void) mAudioTrackServerProxy->obtainBuffer(&buffer, true /*ackFlush*/); 715 } 716 } else { 717 status = BAD_VALUE; 718 } 719 return status; 720} 721 722void AudioFlinger::PlaybackThread::Track::stop() 723{ 724 ALOGV("stop(%d), calling pid %d", mName, IPCThreadState::self()->getCallingPid()); 725 sp<ThreadBase> thread = mThread.promote(); 726 if (thread != 0) { 727 Mutex::Autolock _l(thread->mLock); 728 track_state state = mState; 729 if (state == RESUMING || state == ACTIVE || state == PAUSING || state == PAUSED) { 730 // If the track is not active (PAUSED and buffers full), flush buffers 731 PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); 732 if (playbackThread->mActiveTracks.indexOf(this) < 0) { 733 reset(); 734 mState = STOPPED; 735 } else if (!isFastTrack() && !isOffloaded() && !isDirect()) { 736 mState = STOPPED; 737 } else { 738 // For fast tracks prepareTracks_l() will set state to STOPPING_2 739 // presentation is complete 740 // For an offloaded track this starts a drain and state will 741 // move to STOPPING_2 when drain completes and then STOPPED 742 mState = STOPPING_1; 743 if (isOffloaded()) { 744 mRetryCount = PlaybackThread::kMaxTrackStopRetriesOffload; 745 } 746 } 747 playbackThread->broadcast_l(); 748 ALOGV("not stopping/stopped => stopping/stopped (%d) on thread %p", mName, 749 playbackThread); 750 } 751 } 752} 753 754void AudioFlinger::PlaybackThread::Track::pause() 755{ 756 ALOGV("pause(%d), calling pid %d", mName, IPCThreadState::self()->getCallingPid()); 757 sp<ThreadBase> thread = mThread.promote(); 758 if (thread != 0) { 759 Mutex::Autolock _l(thread->mLock); 760 PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); 761 switch (mState) { 762 case STOPPING_1: 763 case STOPPING_2: 764 if (!isOffloaded()) { 765 /* nothing to do if track is not offloaded */ 766 break; 767 } 768 769 // Offloaded track was draining, we need to carry on draining when resumed 770 mResumeToStopping = true; 771 // fall through... 772 case ACTIVE: 773 case RESUMING: 774 mState = PAUSING; 775 ALOGV("ACTIVE/RESUMING => PAUSING (%d) on thread %p", mName, thread.get()); 776 playbackThread->broadcast_l(); 777 break; 778 779 default: 780 break; 781 } 782 } 783} 784 785void AudioFlinger::PlaybackThread::Track::flush() 786{ 787 ALOGV("flush(%d)", mName); 788 sp<ThreadBase> thread = mThread.promote(); 789 if (thread != 0) { 790 Mutex::Autolock _l(thread->mLock); 791 PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); 792 793 // Flush the ring buffer now if the track is not active in the PlaybackThread. 794 // Otherwise the flush would not be done until the track is resumed. 795 // Requires FastTrack removal be BLOCK_UNTIL_ACKED 796 if (playbackThread->mActiveTracks.indexOf(this) < 0) { 797 (void)mServerProxy->flushBufferIfNeeded(); 798 } 799 800 if (isOffloaded()) { 801 // If offloaded we allow flush during any state except terminated 802 // and keep the track active to avoid problems if user is seeking 803 // rapidly and underlying hardware has a significant delay handling 804 // a pause 805 if (isTerminated()) { 806 return; 807 } 808 809 ALOGV("flush: offload flush"); 810 reset(); 811 812 if (mState == STOPPING_1 || mState == STOPPING_2) { 813 ALOGV("flushed in STOPPING_1 or 2 state, change state to ACTIVE"); 814 mState = ACTIVE; 815 } 816 817 mFlushHwPending = true; 818 mResumeToStopping = false; 819 } else { 820 if (mState != STOPPING_1 && mState != STOPPING_2 && mState != STOPPED && 821 mState != PAUSED && mState != PAUSING && mState != IDLE && mState != FLUSHED) { 822 return; 823 } 824 // No point remaining in PAUSED state after a flush => go to 825 // FLUSHED state 826 mState = FLUSHED; 827 // do not reset the track if it is still in the process of being stopped or paused. 828 // this will be done by prepareTracks_l() when the track is stopped. 829 // prepareTracks_l() will see mState == FLUSHED, then 830 // remove from active track list, reset(), and trigger presentation complete 831 if (isDirect()) { 832 mFlushHwPending = true; 833 } 834 if (playbackThread->mActiveTracks.indexOf(this) < 0) { 835 reset(); 836 } 837 } 838 // Prevent flush being lost if the track is flushed and then resumed 839 // before mixer thread can run. This is important when offloading 840 // because the hardware buffer could hold a large amount of audio 841 playbackThread->broadcast_l(); 842 } 843} 844 845// must be called with thread lock held 846void AudioFlinger::PlaybackThread::Track::flushAck() 847{ 848 if (!isOffloaded() && !isDirect()) 849 return; 850 851 // Clear the client ring buffer so that the app can prime the buffer while paused. 852 // Otherwise it might not get cleared until playback is resumed and obtainBuffer() is called. 853 mServerProxy->flushBufferIfNeeded(); 854 855 mFlushHwPending = false; 856} 857 858void AudioFlinger::PlaybackThread::Track::reset() 859{ 860 // Do not reset twice to avoid discarding data written just after a flush and before 861 // the audioflinger thread detects the track is stopped. 862 if (!mResetDone) { 863 // Force underrun condition to avoid false underrun callback until first data is 864 // written to buffer 865 android_atomic_and(~CBLK_FORCEREADY, &mCblk->mFlags); 866 mFillingUpStatus = FS_FILLING; 867 mResetDone = true; 868 if (mState == FLUSHED) { 869 mState = IDLE; 870 } 871 } 872} 873 874status_t AudioFlinger::PlaybackThread::Track::setParameters(const String8& keyValuePairs) 875{ 876 sp<ThreadBase> thread = mThread.promote(); 877 if (thread == 0) { 878 ALOGE("thread is dead"); 879 return FAILED_TRANSACTION; 880 } else if ((thread->type() == ThreadBase::DIRECT) || 881 (thread->type() == ThreadBase::OFFLOAD)) { 882 return thread->setParameters(keyValuePairs); 883 } else { 884 return PERMISSION_DENIED; 885 } 886} 887 888VolumeShaper::Status AudioFlinger::PlaybackThread::Track::applyVolumeShaper( 889 const sp<VolumeShaper::Configuration>& configuration, 890 const sp<VolumeShaper::Operation>& operation) 891{ 892 // Note: We don't check if Thread exists. 893 894 // mVolumeHandler is thread-safe. 895 return mVolumeHandler->applyVolumeShaper(configuration, operation); 896} 897 898sp<VolumeShaper::State> AudioFlinger::PlaybackThread::Track::getVolumeShaperState(int id) 899{ 900 // Note: We don't check if Thread exists. 901 902 // mVolumeHandler is thread safe. 903 return mVolumeHandler->getVolumeShaperState(id); 904} 905 906status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& timestamp) 907{ 908 if (!isOffloaded() && !isDirect()) { 909 return INVALID_OPERATION; // normal tracks handled through SSQ 910 } 911 sp<ThreadBase> thread = mThread.promote(); 912 if (thread == 0) { 913 return INVALID_OPERATION; 914 } 915 916 Mutex::Autolock _l(thread->mLock); 917 PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); 918 return playbackThread->getTimestamp_l(timestamp); 919} 920 921status_t AudioFlinger::PlaybackThread::Track::attachAuxEffect(int EffectId) 922{ 923 status_t status = DEAD_OBJECT; 924 sp<ThreadBase> thread = mThread.promote(); 925 if (thread != 0) { 926 PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); 927 sp<AudioFlinger> af = mClient->audioFlinger(); 928 929 Mutex::Autolock _l(af->mLock); 930 931 sp<PlaybackThread> srcThread = af->getEffectThread_l(AUDIO_SESSION_OUTPUT_MIX, EffectId); 932 933 if (EffectId != 0 && srcThread != 0 && playbackThread != srcThread.get()) { 934 Mutex::Autolock _dl(playbackThread->mLock); 935 Mutex::Autolock _sl(srcThread->mLock); 936 sp<EffectChain> chain = srcThread->getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX); 937 if (chain == 0) { 938 return INVALID_OPERATION; 939 } 940 941 sp<EffectModule> effect = chain->getEffectFromId_l(EffectId); 942 if (effect == 0) { 943 return INVALID_OPERATION; 944 } 945 srcThread->removeEffect_l(effect); 946 status = playbackThread->addEffect_l(effect); 947 if (status != NO_ERROR) { 948 srcThread->addEffect_l(effect); 949 return INVALID_OPERATION; 950 } 951 // removeEffect_l() has stopped the effect if it was active so it must be restarted 952 if (effect->state() == EffectModule::ACTIVE || 953 effect->state() == EffectModule::STOPPING) { 954 effect->start(); 955 } 956 957 sp<EffectChain> dstChain = effect->chain().promote(); 958 if (dstChain == 0) { 959 srcThread->addEffect_l(effect); 960 return INVALID_OPERATION; 961 } 962 AudioSystem::unregisterEffect(effect->id()); 963 AudioSystem::registerEffect(&effect->desc(), 964 srcThread->id(), 965 dstChain->strategy(), 966 AUDIO_SESSION_OUTPUT_MIX, 967 effect->id()); 968 AudioSystem::setEffectEnabled(effect->id(), effect->isEnabled()); 969 } 970 status = playbackThread->attachAuxEffect(this, EffectId); 971 } 972 return status; 973} 974 975void AudioFlinger::PlaybackThread::Track::setAuxBuffer(int EffectId, int32_t *buffer) 976{ 977 mAuxEffectId = EffectId; 978 mAuxBuffer = buffer; 979} 980 981bool AudioFlinger::PlaybackThread::Track::presentationComplete( 982 int64_t framesWritten, size_t audioHalFrames) 983{ 984 // TODO: improve this based on FrameMap if it exists, to ensure full drain. 985 // This assists in proper timestamp computation as well as wakelock management. 986 987 // a track is considered presented when the total number of frames written to audio HAL 988 // corresponds to the number of frames written when presentationComplete() is called for the 989 // first time (mPresentationCompleteFrames == 0) plus the buffer filling status at that time. 990 // For an offloaded track the HAL+h/w delay is variable so a HAL drain() is used 991 // to detect when all frames have been played. In this case framesWritten isn't 992 // useful because it doesn't always reflect whether there is data in the h/w 993 // buffers, particularly if a track has been paused and resumed during draining 994 ALOGV("presentationComplete() mPresentationCompleteFrames %lld framesWritten %lld", 995 (long long)mPresentationCompleteFrames, (long long)framesWritten); 996 if (mPresentationCompleteFrames == 0) { 997 mPresentationCompleteFrames = framesWritten + audioHalFrames; 998 ALOGV("presentationComplete() reset: mPresentationCompleteFrames %lld audioHalFrames %zu", 999 (long long)mPresentationCompleteFrames, audioHalFrames); 1000 } 1001 1002 bool complete; 1003 if (isOffloaded()) { 1004 complete = true; 1005 } else if (isDirect() || isFastTrack()) { // these do not go through linear map 1006 complete = framesWritten >= (int64_t) mPresentationCompleteFrames; 1007 } else { // Normal tracks, OutputTracks, and PatchTracks 1008 complete = framesWritten >= (int64_t) mPresentationCompleteFrames 1009 && mAudioTrackServerProxy->isDrained(); 1010 } 1011 1012 if (complete) { 1013 triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE); 1014 mAudioTrackServerProxy->setStreamEndDone(); 1015 return true; 1016 } 1017 return false; 1018} 1019 1020void AudioFlinger::PlaybackThread::Track::triggerEvents(AudioSystem::sync_event_t type) 1021{ 1022 for (size_t i = 0; i < mSyncEvents.size(); i++) { 1023 if (mSyncEvents[i]->type() == type) { 1024 mSyncEvents[i]->trigger(); 1025 mSyncEvents.removeAt(i); 1026 i--; 1027 } 1028 } 1029} 1030 1031// implement VolumeBufferProvider interface 1032 1033gain_minifloat_packed_t AudioFlinger::PlaybackThread::Track::getVolumeLR() 1034{ 1035 // called by FastMixer, so not allowed to take any locks, block, or do I/O including logs 1036 ALOG_ASSERT(isFastTrack() && (mCblk != NULL)); 1037 gain_minifloat_packed_t vlr = mAudioTrackServerProxy->getVolumeLR(); 1038 float vl = float_from_gain(gain_minifloat_unpack_left(vlr)); 1039 float vr = float_from_gain(gain_minifloat_unpack_right(vlr)); 1040 // track volumes come from shared memory, so can't be trusted and must be clamped 1041 if (vl > GAIN_FLOAT_UNITY) { 1042 vl = GAIN_FLOAT_UNITY; 1043 } 1044 if (vr > GAIN_FLOAT_UNITY) { 1045 vr = GAIN_FLOAT_UNITY; 1046 } 1047 // now apply the cached master volume and stream type volume; 1048 // this is trusted but lacks any synchronization or barrier so may be stale 1049 float v = mCachedVolume; 1050 vl *= v; 1051 vr *= v; 1052 // re-combine into packed minifloat 1053 vlr = gain_minifloat_pack(gain_from_float(vl), gain_from_float(vr)); 1054 // FIXME look at mute, pause, and stop flags 1055 return vlr; 1056} 1057 1058status_t AudioFlinger::PlaybackThread::Track::setSyncEvent(const sp<SyncEvent>& event) 1059{ 1060 if (isTerminated() || mState == PAUSED || 1061 ((framesReady() == 0) && ((mSharedBuffer != 0) || 1062 (mState == STOPPED)))) { 1063 ALOGW("Track::setSyncEvent() in invalid state %d on session %d %s mode, framesReady %zu", 1064 mState, mSessionId, (mSharedBuffer != 0) ? "static" : "stream", framesReady()); 1065 event->cancel(); 1066 return INVALID_OPERATION; 1067 } 1068 (void) TrackBase::setSyncEvent(event); 1069 return NO_ERROR; 1070} 1071 1072void AudioFlinger::PlaybackThread::Track::invalidate() 1073{ 1074 TrackBase::invalidate(); 1075 signalClientFlag(CBLK_INVALID); 1076} 1077 1078void AudioFlinger::PlaybackThread::Track::disable() 1079{ 1080 signalClientFlag(CBLK_DISABLED); 1081} 1082 1083void AudioFlinger::PlaybackThread::Track::signalClientFlag(int32_t flag) 1084{ 1085 // FIXME should use proxy, and needs work 1086 audio_track_cblk_t* cblk = mCblk; 1087 android_atomic_or(flag, &cblk->mFlags); 1088 android_atomic_release_store(0x40000000, &cblk->mFutex); 1089 // client is not in server, so FUTEX_WAKE is needed instead of FUTEX_WAKE_PRIVATE 1090 (void) syscall(__NR_futex, &cblk->mFutex, FUTEX_WAKE, INT_MAX); 1091} 1092 1093void AudioFlinger::PlaybackThread::Track::signal() 1094{ 1095 sp<ThreadBase> thread = mThread.promote(); 1096 if (thread != 0) { 1097 PlaybackThread *t = (PlaybackThread *)thread.get(); 1098 Mutex::Autolock _l(t->mLock); 1099 t->broadcast_l(); 1100 } 1101} 1102 1103//To be called with thread lock held 1104bool AudioFlinger::PlaybackThread::Track::isResumePending() { 1105 1106 if (mState == RESUMING) 1107 return true; 1108 /* Resume is pending if track was stopping before pause was called */ 1109 if (mState == STOPPING_1 && 1110 mResumeToStopping) 1111 return true; 1112 1113 return false; 1114} 1115 1116//To be called with thread lock held 1117void AudioFlinger::PlaybackThread::Track::resumeAck() { 1118 1119 1120 if (mState == RESUMING) 1121 mState = ACTIVE; 1122 1123 // Other possibility of pending resume is stopping_1 state 1124 // Do not update the state from stopping as this prevents 1125 // drain being called. 1126 if (mState == STOPPING_1) { 1127 mResumeToStopping = false; 1128 } 1129} 1130 1131//To be called with thread lock held 1132void AudioFlinger::PlaybackThread::Track::updateTrackFrameInfo( 1133 int64_t trackFramesReleased, int64_t sinkFramesWritten, 1134 const ExtendedTimestamp &timeStamp) { 1135 //update frame map 1136 mFrameMap.push(trackFramesReleased, sinkFramesWritten); 1137 1138 // adjust server times and set drained state. 1139 // 1140 // Our timestamps are only updated when the track is on the Thread active list. 1141 // We need to ensure that tracks are not removed before full drain. 1142 ExtendedTimestamp local = timeStamp; 1143 bool checked = false; 1144 for (int i = ExtendedTimestamp::LOCATION_MAX - 1; 1145 i >= ExtendedTimestamp::LOCATION_SERVER; --i) { 1146 // Lookup the track frame corresponding to the sink frame position. 1147 if (local.mTimeNs[i] > 0) { 1148 local.mPosition[i] = mFrameMap.findX(local.mPosition[i]); 1149 // check drain state from the latest stage in the pipeline. 1150 if (!checked && i <= ExtendedTimestamp::LOCATION_KERNEL) { 1151 mAudioTrackServerProxy->setDrained( 1152 local.mPosition[i] >= mAudioTrackServerProxy->framesReleased()); 1153 checked = true; 1154 } 1155 } 1156 } 1157 if (!checked) { // no server info, assume drained. 1158 mAudioTrackServerProxy->setDrained(true); 1159 } 1160 // Set correction for flushed frames that are not accounted for in released. 1161 local.mFlushed = mAudioTrackServerProxy->framesFlushed(); 1162 mServerProxy->setTimestamp(local); 1163} 1164 1165// ---------------------------------------------------------------------------- 1166 1167AudioFlinger::PlaybackThread::OutputTrack::OutputTrack( 1168 PlaybackThread *playbackThread, 1169 DuplicatingThread *sourceThread, 1170 uint32_t sampleRate, 1171 audio_format_t format, 1172 audio_channel_mask_t channelMask, 1173 size_t frameCount, 1174 uid_t uid) 1175 : Track(playbackThread, NULL, AUDIO_STREAM_PATCH, 1176 sampleRate, format, channelMask, frameCount, 1177 NULL, 0, AUDIO_SESSION_NONE, uid, AUDIO_OUTPUT_FLAG_NONE, 1178 TYPE_OUTPUT), 1179 mActive(false), mSourceThread(sourceThread) 1180{ 1181 1182 if (mCblk != NULL) { 1183 mOutBuffer.frameCount = 0; 1184 playbackThread->mTracks.add(this); 1185 ALOGV("OutputTrack constructor mCblk %p, mBuffer %p, " 1186 "frameCount %zu, mChannelMask 0x%08x", 1187 mCblk, mBuffer, 1188 frameCount, mChannelMask); 1189 // since client and server are in the same process, 1190 // the buffer has the same virtual address on both sides 1191 mClientProxy = new AudioTrackClientProxy(mCblk, mBuffer, mFrameCount, mFrameSize, 1192 true /*clientInServer*/); 1193 mClientProxy->setVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY); 1194 mClientProxy->setSendLevel(0.0); 1195 mClientProxy->setSampleRate(sampleRate); 1196 } else { 1197 ALOGW("Error creating output track on thread %p", playbackThread); 1198 } 1199} 1200 1201AudioFlinger::PlaybackThread::OutputTrack::~OutputTrack() 1202{ 1203 clearBufferQueue(); 1204 // superclass destructor will now delete the server proxy and shared memory both refer to 1205} 1206 1207status_t AudioFlinger::PlaybackThread::OutputTrack::start(AudioSystem::sync_event_t event, 1208 audio_session_t triggerSession) 1209{ 1210 status_t status = Track::start(event, triggerSession); 1211 if (status != NO_ERROR) { 1212 return status; 1213 } 1214 1215 mActive = true; 1216 mRetryCount = 127; 1217 return status; 1218} 1219 1220void AudioFlinger::PlaybackThread::OutputTrack::stop() 1221{ 1222 Track::stop(); 1223 clearBufferQueue(); 1224 mOutBuffer.frameCount = 0; 1225 mActive = false; 1226} 1227 1228bool AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t frames) 1229{ 1230 Buffer *pInBuffer; 1231 Buffer inBuffer; 1232 bool outputBufferFull = false; 1233 inBuffer.frameCount = frames; 1234 inBuffer.raw = data; 1235 1236 uint32_t waitTimeLeftMs = mSourceThread->waitTimeMs(); 1237 1238 if (!mActive && frames != 0) { 1239 (void) start(); 1240 } 1241 1242 while (waitTimeLeftMs) { 1243 // First write pending buffers, then new data 1244 if (mBufferQueue.size()) { 1245 pInBuffer = mBufferQueue.itemAt(0); 1246 } else { 1247 pInBuffer = &inBuffer; 1248 } 1249 1250 if (pInBuffer->frameCount == 0) { 1251 break; 1252 } 1253 1254 if (mOutBuffer.frameCount == 0) { 1255 mOutBuffer.frameCount = pInBuffer->frameCount; 1256 nsecs_t startTime = systemTime(); 1257 status_t status = obtainBuffer(&mOutBuffer, waitTimeLeftMs); 1258 if (status != NO_ERROR && status != NOT_ENOUGH_DATA) { 1259 ALOGV("OutputTrack::write() %p thread %p no more output buffers; status %d", this, 1260 mThread.unsafe_get(), status); 1261 outputBufferFull = true; 1262 break; 1263 } 1264 uint32_t waitTimeMs = (uint32_t)ns2ms(systemTime() - startTime); 1265 if (waitTimeLeftMs >= waitTimeMs) { 1266 waitTimeLeftMs -= waitTimeMs; 1267 } else { 1268 waitTimeLeftMs = 0; 1269 } 1270 if (status == NOT_ENOUGH_DATA) { 1271 restartIfDisabled(); 1272 continue; 1273 } 1274 } 1275 1276 uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount : 1277 pInBuffer->frameCount; 1278 memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * mFrameSize); 1279 Proxy::Buffer buf; 1280 buf.mFrameCount = outFrames; 1281 buf.mRaw = NULL; 1282 mClientProxy->releaseBuffer(&buf); 1283 restartIfDisabled(); 1284 pInBuffer->frameCount -= outFrames; 1285 pInBuffer->raw = (int8_t *)pInBuffer->raw + outFrames * mFrameSize; 1286 mOutBuffer.frameCount -= outFrames; 1287 mOutBuffer.raw = (int8_t *)mOutBuffer.raw + outFrames * mFrameSize; 1288 1289 if (pInBuffer->frameCount == 0) { 1290 if (mBufferQueue.size()) { 1291 mBufferQueue.removeAt(0); 1292 free(pInBuffer->mBuffer); 1293 delete pInBuffer; 1294 ALOGV("OutputTrack::write() %p thread %p released overflow buffer %zu", this, 1295 mThread.unsafe_get(), mBufferQueue.size()); 1296 } else { 1297 break; 1298 } 1299 } 1300 } 1301 1302 // If we could not write all frames, allocate a buffer and queue it for next time. 1303 if (inBuffer.frameCount) { 1304 sp<ThreadBase> thread = mThread.promote(); 1305 if (thread != 0 && !thread->standby()) { 1306 if (mBufferQueue.size() < kMaxOverFlowBuffers) { 1307 pInBuffer = new Buffer; 1308 pInBuffer->mBuffer = malloc(inBuffer.frameCount * mFrameSize); 1309 pInBuffer->frameCount = inBuffer.frameCount; 1310 pInBuffer->raw = pInBuffer->mBuffer; 1311 memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * mFrameSize); 1312 mBufferQueue.add(pInBuffer); 1313 ALOGV("OutputTrack::write() %p thread %p adding overflow buffer %zu", this, 1314 mThread.unsafe_get(), mBufferQueue.size()); 1315 } else { 1316 ALOGW("OutputTrack::write() %p thread %p no more overflow buffers", 1317 mThread.unsafe_get(), this); 1318 } 1319 } 1320 } 1321 1322 // Calling write() with a 0 length buffer means that no more data will be written: 1323 // We rely on stop() to set the appropriate flags to allow the remaining frames to play out. 1324 if (frames == 0 && mBufferQueue.size() == 0 && mActive) { 1325 stop(); 1326 } 1327 1328 return outputBufferFull; 1329} 1330 1331status_t AudioFlinger::PlaybackThread::OutputTrack::obtainBuffer( 1332 AudioBufferProvider::Buffer* buffer, uint32_t waitTimeMs) 1333{ 1334 ClientProxy::Buffer buf; 1335 buf.mFrameCount = buffer->frameCount; 1336 struct timespec timeout; 1337 timeout.tv_sec = waitTimeMs / 1000; 1338 timeout.tv_nsec = (int) (waitTimeMs % 1000) * 1000000; 1339 status_t status = mClientProxy->obtainBuffer(&buf, &timeout); 1340 buffer->frameCount = buf.mFrameCount; 1341 buffer->raw = buf.mRaw; 1342 return status; 1343} 1344 1345void AudioFlinger::PlaybackThread::OutputTrack::clearBufferQueue() 1346{ 1347 size_t size = mBufferQueue.size(); 1348 1349 for (size_t i = 0; i < size; i++) { 1350 Buffer *pBuffer = mBufferQueue.itemAt(i); 1351 free(pBuffer->mBuffer); 1352 delete pBuffer; 1353 } 1354 mBufferQueue.clear(); 1355} 1356 1357void AudioFlinger::PlaybackThread::OutputTrack::restartIfDisabled() 1358{ 1359 int32_t flags = android_atomic_and(~CBLK_DISABLED, &mCblk->mFlags); 1360 if (mActive && (flags & CBLK_DISABLED)) { 1361 start(); 1362 } 1363} 1364 1365AudioFlinger::PlaybackThread::PatchTrack::PatchTrack(PlaybackThread *playbackThread, 1366 audio_stream_type_t streamType, 1367 uint32_t sampleRate, 1368 audio_channel_mask_t channelMask, 1369 audio_format_t format, 1370 size_t frameCount, 1371 void *buffer, 1372 audio_output_flags_t flags) 1373 : Track(playbackThread, NULL, streamType, 1374 sampleRate, format, channelMask, frameCount, 1375 buffer, 0, AUDIO_SESSION_NONE, getuid(), flags, TYPE_PATCH), 1376 mProxy(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, true, true)) 1377{ 1378 uint64_t mixBufferNs = ((uint64_t)2 * playbackThread->frameCount() * 1000000000) / 1379 playbackThread->sampleRate(); 1380 mPeerTimeout.tv_sec = mixBufferNs / 1000000000; 1381 mPeerTimeout.tv_nsec = (int) (mixBufferNs % 1000000000); 1382 1383 ALOGV("PatchTrack %p sampleRate %d mPeerTimeout %d.%03d sec", 1384 this, sampleRate, 1385 (int)mPeerTimeout.tv_sec, 1386 (int)(mPeerTimeout.tv_nsec / 1000000)); 1387} 1388 1389AudioFlinger::PlaybackThread::PatchTrack::~PatchTrack() 1390{ 1391} 1392 1393status_t AudioFlinger::PlaybackThread::PatchTrack::start(AudioSystem::sync_event_t event, 1394 audio_session_t triggerSession) 1395{ 1396 status_t status = Track::start(event, triggerSession); 1397 if (status != NO_ERROR) { 1398 return status; 1399 } 1400 android_atomic_and(~CBLK_DISABLED, &mCblk->mFlags); 1401 return status; 1402} 1403 1404// AudioBufferProvider interface 1405status_t AudioFlinger::PlaybackThread::PatchTrack::getNextBuffer( 1406 AudioBufferProvider::Buffer* buffer) 1407{ 1408 ALOG_ASSERT(mPeerProxy != 0, "PatchTrack::getNextBuffer() called without peer proxy"); 1409 Proxy::Buffer buf; 1410 buf.mFrameCount = buffer->frameCount; 1411 status_t status = mPeerProxy->obtainBuffer(&buf, &mPeerTimeout); 1412 ALOGV_IF(status != NO_ERROR, "PatchTrack() %p getNextBuffer status %d", this, status); 1413 buffer->frameCount = buf.mFrameCount; 1414 if (buf.mFrameCount == 0) { 1415 return WOULD_BLOCK; 1416 } 1417 status = Track::getNextBuffer(buffer); 1418 return status; 1419} 1420 1421void AudioFlinger::PlaybackThread::PatchTrack::releaseBuffer(AudioBufferProvider::Buffer* buffer) 1422{ 1423 ALOG_ASSERT(mPeerProxy != 0, "PatchTrack::releaseBuffer() called without peer proxy"); 1424 Proxy::Buffer buf; 1425 buf.mFrameCount = buffer->frameCount; 1426 buf.mRaw = buffer->raw; 1427 mPeerProxy->releaseBuffer(&buf); 1428 TrackBase::releaseBuffer(buffer); 1429} 1430 1431status_t AudioFlinger::PlaybackThread::PatchTrack::obtainBuffer(Proxy::Buffer* buffer, 1432 const struct timespec *timeOut) 1433{ 1434 status_t status = NO_ERROR; 1435 static const int32_t kMaxTries = 5; 1436 int32_t tryCounter = kMaxTries; 1437 do { 1438 if (status == NOT_ENOUGH_DATA) { 1439 restartIfDisabled(); 1440 } 1441 status = mProxy->obtainBuffer(buffer, timeOut); 1442 } while ((status == NOT_ENOUGH_DATA) && (tryCounter-- > 0)); 1443 return status; 1444} 1445 1446void AudioFlinger::PlaybackThread::PatchTrack::releaseBuffer(Proxy::Buffer* buffer) 1447{ 1448 mProxy->releaseBuffer(buffer); 1449 restartIfDisabled(); 1450 android_atomic_or(CBLK_FORCEREADY, &mCblk->mFlags); 1451} 1452 1453void AudioFlinger::PlaybackThread::PatchTrack::restartIfDisabled() 1454{ 1455 if (android_atomic_and(~CBLK_DISABLED, &mCblk->mFlags) & CBLK_DISABLED) { 1456 ALOGW("PatchTrack::releaseBuffer() disabled due to previous underrun, restarting"); 1457 start(); 1458 } 1459} 1460 1461// ---------------------------------------------------------------------------- 1462// Record 1463// ---------------------------------------------------------------------------- 1464 1465AudioFlinger::RecordHandle::RecordHandle( 1466 const sp<AudioFlinger::RecordThread::RecordTrack>& recordTrack) 1467 : BnAudioRecord(), 1468 mRecordTrack(recordTrack) 1469{ 1470} 1471 1472AudioFlinger::RecordHandle::~RecordHandle() { 1473 stop_nonvirtual(); 1474 mRecordTrack->destroy(); 1475} 1476 1477status_t AudioFlinger::RecordHandle::start(int /*AudioSystem::sync_event_t*/ event, 1478 audio_session_t triggerSession) { 1479 ALOGV("RecordHandle::start()"); 1480 return mRecordTrack->start((AudioSystem::sync_event_t)event, triggerSession); 1481} 1482 1483void AudioFlinger::RecordHandle::stop() { 1484 stop_nonvirtual(); 1485} 1486 1487void AudioFlinger::RecordHandle::stop_nonvirtual() { 1488 ALOGV("RecordHandle::stop()"); 1489 mRecordTrack->stop(); 1490} 1491 1492status_t AudioFlinger::RecordHandle::onTransact( 1493 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) 1494{ 1495 return BnAudioRecord::onTransact(code, data, reply, flags); 1496} 1497 1498// ---------------------------------------------------------------------------- 1499 1500// RecordTrack constructor must be called with AudioFlinger::mLock and ThreadBase::mLock held 1501AudioFlinger::RecordThread::RecordTrack::RecordTrack( 1502 RecordThread *thread, 1503 const sp<Client>& client, 1504 uint32_t sampleRate, 1505 audio_format_t format, 1506 audio_channel_mask_t channelMask, 1507 size_t frameCount, 1508 void *buffer, 1509 audio_session_t sessionId, 1510 uid_t uid, 1511 audio_input_flags_t flags, 1512 track_type type, 1513 audio_port_handle_t portId) 1514 : TrackBase(thread, client, sampleRate, format, 1515 channelMask, frameCount, buffer, sessionId, uid, false /*isOut*/, 1516 (type == TYPE_DEFAULT) ? 1517 ((flags & AUDIO_INPUT_FLAG_FAST) ? ALLOC_PIPE : ALLOC_CBLK) : 1518 ((buffer == NULL) ? ALLOC_LOCAL : ALLOC_NONE), 1519 type, portId), 1520 mOverflow(false), 1521 mFramesToDrop(0), 1522 mResamplerBufferProvider(NULL), // initialize in case of early constructor exit 1523 mRecordBufferConverter(NULL), 1524 mFlags(flags) 1525{ 1526 if (mCblk == NULL) { 1527 return; 1528 } 1529 1530 mRecordBufferConverter = new RecordBufferConverter( 1531 thread->mChannelMask, thread->mFormat, thread->mSampleRate, 1532 channelMask, format, sampleRate); 1533 // Check if the RecordBufferConverter construction was successful. 1534 // If not, don't continue with construction. 1535 // 1536 // NOTE: It would be extremely rare that the record track cannot be created 1537 // for the current device, but a pending or future device change would make 1538 // the record track configuration valid. 1539 if (mRecordBufferConverter->initCheck() != NO_ERROR) { 1540 ALOGE("RecordTrack unable to create record buffer converter"); 1541 return; 1542 } 1543 1544 mServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount, 1545 mFrameSize, !isExternalTrack()); 1546 1547 mResamplerBufferProvider = new ResamplerBufferProvider(this); 1548 1549 if (flags & AUDIO_INPUT_FLAG_FAST) { 1550 ALOG_ASSERT(thread->mFastTrackAvail); 1551 thread->mFastTrackAvail = false; 1552 } 1553} 1554 1555AudioFlinger::RecordThread::RecordTrack::~RecordTrack() 1556{ 1557 ALOGV("%s", __func__); 1558 delete mRecordBufferConverter; 1559 delete mResamplerBufferProvider; 1560} 1561 1562status_t AudioFlinger::RecordThread::RecordTrack::initCheck() const 1563{ 1564 status_t status = TrackBase::initCheck(); 1565 if (status == NO_ERROR && mServerProxy == 0) { 1566 status = BAD_VALUE; 1567 } 1568 return status; 1569} 1570 1571// AudioBufferProvider interface 1572status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer) 1573{ 1574 ServerProxy::Buffer buf; 1575 buf.mFrameCount = buffer->frameCount; 1576 status_t status = mServerProxy->obtainBuffer(&buf); 1577 buffer->frameCount = buf.mFrameCount; 1578 buffer->raw = buf.mRaw; 1579 if (buf.mFrameCount == 0) { 1580 // FIXME also wake futex so that overrun is noticed more quickly 1581 (void) android_atomic_or(CBLK_OVERRUN, &mCblk->mFlags); 1582 } 1583 return status; 1584} 1585 1586status_t AudioFlinger::RecordThread::RecordTrack::start(AudioSystem::sync_event_t event, 1587 audio_session_t triggerSession) 1588{ 1589 sp<ThreadBase> thread = mThread.promote(); 1590 if (thread != 0) { 1591 RecordThread *recordThread = (RecordThread *)thread.get(); 1592 return recordThread->start(this, event, triggerSession); 1593 } else { 1594 return BAD_VALUE; 1595 } 1596} 1597 1598void AudioFlinger::RecordThread::RecordTrack::stop() 1599{ 1600 sp<ThreadBase> thread = mThread.promote(); 1601 if (thread != 0) { 1602 RecordThread *recordThread = (RecordThread *)thread.get(); 1603 if (recordThread->stop(this) && isExternalTrack()) { 1604 AudioSystem::stopInput(mThreadIoHandle, mSessionId); 1605 } 1606 } 1607} 1608 1609void AudioFlinger::RecordThread::RecordTrack::destroy() 1610{ 1611 // see comments at AudioFlinger::PlaybackThread::Track::destroy() 1612 sp<RecordTrack> keep(this); 1613 { 1614 if (isExternalTrack()) { 1615 if (mState == ACTIVE || mState == RESUMING) { 1616 AudioSystem::stopInput(mThreadIoHandle, mSessionId); 1617 } 1618 AudioSystem::releaseInput(mThreadIoHandle, mSessionId); 1619 } 1620 sp<ThreadBase> thread = mThread.promote(); 1621 if (thread != 0) { 1622 Mutex::Autolock _l(thread->mLock); 1623 RecordThread *recordThread = (RecordThread *) thread.get(); 1624 recordThread->destroyTrack_l(this); 1625 } 1626 } 1627} 1628 1629void AudioFlinger::RecordThread::RecordTrack::invalidate() 1630{ 1631 TrackBase::invalidate(); 1632 // FIXME should use proxy, and needs work 1633 audio_track_cblk_t* cblk = mCblk; 1634 android_atomic_or(CBLK_INVALID, &cblk->mFlags); 1635 android_atomic_release_store(0x40000000, &cblk->mFutex); 1636 // client is not in server, so FUTEX_WAKE is needed instead of FUTEX_WAKE_PRIVATE 1637 (void) syscall(__NR_futex, &cblk->mFutex, FUTEX_WAKE, INT_MAX); 1638} 1639 1640 1641/*static*/ void AudioFlinger::RecordThread::RecordTrack::appendDumpHeader(String8& result) 1642{ 1643 result.append(" Active Client Fmt Chn mask Session S Server fCount SRate\n"); 1644} 1645 1646void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size, bool active) 1647{ 1648 snprintf(buffer, size, " %6s %6u %3u %08X %7u %1d %08X %6zu %5u\n", 1649 active ? "yes" : "no", 1650 (mClient == 0) ? getpid_cached : mClient->pid(), 1651 mFormat, 1652 mChannelMask, 1653 mSessionId, 1654 mState, 1655 mCblk->mServer, 1656 mFrameCount, 1657 mSampleRate); 1658 1659} 1660 1661void AudioFlinger::RecordThread::RecordTrack::handleSyncStartEvent(const sp<SyncEvent>& event) 1662{ 1663 if (event == mSyncStartEvent) { 1664 ssize_t framesToDrop = 0; 1665 sp<ThreadBase> threadBase = mThread.promote(); 1666 if (threadBase != 0) { 1667 // TODO: use actual buffer filling status instead of 2 buffers when info is available 1668 // from audio HAL 1669 framesToDrop = threadBase->mFrameCount * 2; 1670 } 1671 mFramesToDrop = framesToDrop; 1672 } 1673} 1674 1675void AudioFlinger::RecordThread::RecordTrack::clearSyncStartEvent() 1676{ 1677 if (mSyncStartEvent != 0) { 1678 mSyncStartEvent->cancel(); 1679 mSyncStartEvent.clear(); 1680 } 1681 mFramesToDrop = 0; 1682} 1683 1684void AudioFlinger::RecordThread::RecordTrack::updateTrackFrameInfo( 1685 int64_t trackFramesReleased, int64_t sourceFramesRead, 1686 uint32_t halSampleRate, const ExtendedTimestamp ×tamp) 1687{ 1688 ExtendedTimestamp local = timestamp; 1689 1690 // Convert HAL frames to server-side track frames at track sample rate. 1691 // We use trackFramesReleased and sourceFramesRead as an anchor point. 1692 for (int i = ExtendedTimestamp::LOCATION_SERVER; i < ExtendedTimestamp::LOCATION_MAX; ++i) { 1693 if (local.mTimeNs[i] != 0) { 1694 const int64_t relativeServerFrames = local.mPosition[i] - sourceFramesRead; 1695 const int64_t relativeTrackFrames = relativeServerFrames 1696 * mSampleRate / halSampleRate; // TODO: potential computation overflow 1697 local.mPosition[i] = relativeTrackFrames + trackFramesReleased; 1698 } 1699 } 1700 mServerProxy->setTimestamp(local); 1701} 1702 1703AudioFlinger::RecordThread::PatchRecord::PatchRecord(RecordThread *recordThread, 1704 uint32_t sampleRate, 1705 audio_channel_mask_t channelMask, 1706 audio_format_t format, 1707 size_t frameCount, 1708 void *buffer, 1709 audio_input_flags_t flags) 1710 : RecordTrack(recordThread, NULL, sampleRate, format, channelMask, frameCount, 1711 buffer, AUDIO_SESSION_NONE, getuid(), flags, TYPE_PATCH), 1712 mProxy(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, false, true)) 1713{ 1714 uint64_t mixBufferNs = ((uint64_t)2 * recordThread->frameCount() * 1000000000) / 1715 recordThread->sampleRate(); 1716 mPeerTimeout.tv_sec = mixBufferNs / 1000000000; 1717 mPeerTimeout.tv_nsec = (int) (mixBufferNs % 1000000000); 1718 1719 ALOGV("PatchRecord %p sampleRate %d mPeerTimeout %d.%03d sec", 1720 this, sampleRate, 1721 (int)mPeerTimeout.tv_sec, 1722 (int)(mPeerTimeout.tv_nsec / 1000000)); 1723} 1724 1725AudioFlinger::RecordThread::PatchRecord::~PatchRecord() 1726{ 1727} 1728 1729// AudioBufferProvider interface 1730status_t AudioFlinger::RecordThread::PatchRecord::getNextBuffer( 1731 AudioBufferProvider::Buffer* buffer) 1732{ 1733 ALOG_ASSERT(mPeerProxy != 0, "PatchRecord::getNextBuffer() called without peer proxy"); 1734 Proxy::Buffer buf; 1735 buf.mFrameCount = buffer->frameCount; 1736 status_t status = mPeerProxy->obtainBuffer(&buf, &mPeerTimeout); 1737 ALOGV_IF(status != NO_ERROR, 1738 "PatchRecord() %p mPeerProxy->obtainBuffer status %d", this, status); 1739 buffer->frameCount = buf.mFrameCount; 1740 if (buf.mFrameCount == 0) { 1741 return WOULD_BLOCK; 1742 } 1743 status = RecordTrack::getNextBuffer(buffer); 1744 return status; 1745} 1746 1747void AudioFlinger::RecordThread::PatchRecord::releaseBuffer(AudioBufferProvider::Buffer* buffer) 1748{ 1749 ALOG_ASSERT(mPeerProxy != 0, "PatchRecord::releaseBuffer() called without peer proxy"); 1750 Proxy::Buffer buf; 1751 buf.mFrameCount = buffer->frameCount; 1752 buf.mRaw = buffer->raw; 1753 mPeerProxy->releaseBuffer(&buf); 1754 TrackBase::releaseBuffer(buffer); 1755} 1756 1757status_t AudioFlinger::RecordThread::PatchRecord::obtainBuffer(Proxy::Buffer* buffer, 1758 const struct timespec *timeOut) 1759{ 1760 return mProxy->obtainBuffer(buffer, timeOut); 1761} 1762 1763void AudioFlinger::RecordThread::PatchRecord::releaseBuffer(Proxy::Buffer* buffer) 1764{ 1765 mProxy->releaseBuffer(buffer); 1766} 1767 1768 1769 1770AudioFlinger::MmapThread::MmapTrack::MmapTrack(ThreadBase *thread, 1771 uint32_t sampleRate, 1772 audio_format_t format, 1773 audio_channel_mask_t channelMask, 1774 audio_session_t sessionId, 1775 uid_t uid, 1776 audio_port_handle_t portId) 1777 : TrackBase(thread, NULL, sampleRate, format, 1778 channelMask, 0, NULL, sessionId, uid, false, 1779 ALLOC_NONE, 1780 TYPE_DEFAULT, portId) 1781{ 1782} 1783 1784AudioFlinger::MmapThread::MmapTrack::~MmapTrack() 1785{ 1786} 1787 1788status_t AudioFlinger::MmapThread::MmapTrack::initCheck() const 1789{ 1790 return NO_ERROR; 1791} 1792 1793status_t AudioFlinger::MmapThread::MmapTrack::start(AudioSystem::sync_event_t event __unused, 1794 audio_session_t triggerSession __unused) 1795{ 1796 return NO_ERROR; 1797} 1798 1799void AudioFlinger::MmapThread::MmapTrack::stop() 1800{ 1801} 1802 1803// AudioBufferProvider interface 1804status_t AudioFlinger::MmapThread::MmapTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer) 1805{ 1806 buffer->frameCount = 0; 1807 buffer->raw = nullptr; 1808 return INVALID_OPERATION; 1809} 1810 1811// ExtendedAudioBufferProvider interface 1812size_t AudioFlinger::MmapThread::MmapTrack::framesReady() const { 1813 return 0; 1814} 1815 1816int64_t AudioFlinger::MmapThread::MmapTrack::framesReleased() const 1817{ 1818 return 0; 1819} 1820 1821void AudioFlinger::MmapThread::MmapTrack::onTimestamp(const ExtendedTimestamp ×tamp __unused) 1822{ 1823} 1824 1825/*static*/ void AudioFlinger::MmapThread::MmapTrack::appendDumpHeader(String8& result) 1826{ 1827 result.append(" Client Fmt Chn mask SRate\n"); 1828} 1829 1830void AudioFlinger::MmapThread::MmapTrack::dump(char* buffer, size_t size) 1831{ 1832 snprintf(buffer, size, " %6u %3u %08X %5u\n", 1833 mUid, 1834 mFormat, 1835 mChannelMask, 1836 mSampleRate); 1837 1838} 1839 1840} // namespace android 1841