1 /* 2 ** 3 ** Copyright 2018, 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 //#define LOG_NDEBUG 0 19 #define LOG_TAG "MediaPlayer2AudioOutput" 20 #include <mediaplayer2/MediaPlayer2AudioOutput.h> 21 22 #include <cutils/properties.h> // for property_get 23 #include <utils/Log.h> 24 25 #include <media/stagefright/foundation/ADebug.h> 26 27 namespace { 28 29 const float kMaxRequiredSpeed = 8.0f; // for PCM tracks allow up to 8x speedup. 30 31 } // anonymous namespace 32 33 namespace android { 34 35 // TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround 36 /* static */ int MediaPlayer2AudioOutput::mMinBufferCount = 4; 37 /* static */ bool MediaPlayer2AudioOutput::mIsOnEmulator = false; 38 39 status_t MediaPlayer2AudioOutput::dump(int fd, const Vector<String16>& args) const { 40 const size_t SIZE = 256; 41 char buffer[SIZE]; 42 String8 result; 43 44 result.append(" MediaPlayer2AudioOutput\n"); 45 snprintf(buffer, 255, " volume(%f)\n", mVolume); 46 result.append(buffer); 47 snprintf(buffer, 255, " msec per frame(%f), latency (%d)\n", 48 mMsecsPerFrame, (mJAudioTrack != nullptr) ? mJAudioTrack->latency() : -1); 49 result.append(buffer); 50 snprintf(buffer, 255, " aux effect id(%d), send level (%f)\n", 51 mAuxEffectId, mSendLevel); 52 result.append(buffer); 53 54 ::write(fd, result.string(), result.size()); 55 if (mJAudioTrack != nullptr) { 56 mJAudioTrack->dump(fd, args); 57 } 58 return NO_ERROR; 59 } 60 61 MediaPlayer2AudioOutput::MediaPlayer2AudioOutput(int32_t sessionId, uid_t uid, int pid, 62 const jobject attributes) 63 : mCallback(nullptr), 64 mCallbackCookie(nullptr), 65 mCallbackData(nullptr), 66 mVolume(1.0), 67 mPlaybackRate(AUDIO_PLAYBACK_RATE_DEFAULT), 68 mSampleRateHz(0), 69 mMsecsPerFrame(0), 70 mFrameSize(0), 71 mSessionId(sessionId), 72 mUid(uid), 73 mPid(pid), 74 mSendLevel(0.0), 75 mAuxEffectId(0), 76 mFlags(AUDIO_OUTPUT_FLAG_NONE) { 77 ALOGV("MediaPlayer2AudioOutput(%d)", sessionId); 78 79 if (attributes != nullptr) { 80 mAttributes = new JObjectHolder(attributes); 81 } 82 83 setMinBufferCount(); 84 mRoutingDelegates.clear(); 85 } 86 87 MediaPlayer2AudioOutput::~MediaPlayer2AudioOutput() { 88 close(); 89 delete mCallbackData; 90 } 91 92 //static 93 void MediaPlayer2AudioOutput::setMinBufferCount() { 94 char value[PROPERTY_VALUE_MAX]; 95 if (property_get("ro.kernel.qemu", value, 0)) { 96 mIsOnEmulator = true; 97 mMinBufferCount = 12; // to prevent systematic buffer underrun for emulator 98 } 99 } 100 101 // static 102 bool MediaPlayer2AudioOutput::isOnEmulator() { 103 setMinBufferCount(); // benign race wrt other threads 104 return mIsOnEmulator; 105 } 106 107 // static 108 int MediaPlayer2AudioOutput::getMinBufferCount() { 109 setMinBufferCount(); // benign race wrt other threads 110 return mMinBufferCount; 111 } 112 113 ssize_t MediaPlayer2AudioOutput::bufferSize() const { 114 Mutex::Autolock lock(mLock); 115 if (mJAudioTrack == nullptr) { 116 return NO_INIT; 117 } 118 return mJAudioTrack->frameCount() * mFrameSize; 119 } 120 121 ssize_t MediaPlayer2AudioOutput::frameCount() const { 122 Mutex::Autolock lock(mLock); 123 if (mJAudioTrack == nullptr) { 124 return NO_INIT; 125 } 126 return mJAudioTrack->frameCount(); 127 } 128 129 ssize_t MediaPlayer2AudioOutput::channelCount() const { 130 Mutex::Autolock lock(mLock); 131 if (mJAudioTrack == nullptr) { 132 return NO_INIT; 133 } 134 return mJAudioTrack->channelCount(); 135 } 136 137 ssize_t MediaPlayer2AudioOutput::frameSize() const { 138 Mutex::Autolock lock(mLock); 139 if (mJAudioTrack == nullptr) { 140 return NO_INIT; 141 } 142 return mFrameSize; 143 } 144 145 uint32_t MediaPlayer2AudioOutput::latency () const { 146 Mutex::Autolock lock(mLock); 147 if (mJAudioTrack == nullptr) { 148 return 0; 149 } 150 return mJAudioTrack->latency(); 151 } 152 153 float MediaPlayer2AudioOutput::msecsPerFrame() const { 154 Mutex::Autolock lock(mLock); 155 return mMsecsPerFrame; 156 } 157 158 status_t MediaPlayer2AudioOutput::getPosition(uint32_t *position) const { 159 Mutex::Autolock lock(mLock); 160 if (mJAudioTrack == nullptr) { 161 return NO_INIT; 162 } 163 return mJAudioTrack->getPosition(position); 164 } 165 166 status_t MediaPlayer2AudioOutput::getTimestamp(AudioTimestamp &ts) const { 167 Mutex::Autolock lock(mLock); 168 if (mJAudioTrack == nullptr) { 169 return NO_INIT; 170 } 171 return mJAudioTrack->getTimestamp(ts); 172 } 173 174 // TODO: Remove unnecessary calls to getPlayedOutDurationUs() 175 // as it acquires locks and may query the audio driver. 176 // 177 // Some calls could conceivably retrieve extrapolated data instead of 178 // accessing getTimestamp() or getPosition() every time a data buffer with 179 // a media time is received. 180 // 181 // Calculate duration of played samples if played at normal rate (i.e., 1.0). 182 int64_t MediaPlayer2AudioOutput::getPlayedOutDurationUs(int64_t nowUs) const { 183 Mutex::Autolock lock(mLock); 184 if (mJAudioTrack == nullptr || mSampleRateHz == 0) { 185 return 0; 186 } 187 188 uint32_t numFramesPlayed; 189 int64_t numFramesPlayedAtUs; 190 AudioTimestamp ts; 191 192 status_t res = mJAudioTrack->getTimestamp(ts); 193 194 if (res == OK) { // case 1: mixing audio tracks and offloaded tracks. 195 numFramesPlayed = ts.mPosition; 196 numFramesPlayedAtUs = ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000; 197 //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAtUs); 198 } else { // case 2: transitory state on start of a new track 199 // case 3: transitory at new track or audio fast tracks. 200 numFramesPlayed = 0; 201 numFramesPlayedAtUs = nowUs; 202 //ALOGD("getTimestamp: WOULD_BLOCK %d %lld", 203 // numFramesPlayed, (long long)numFramesPlayedAtUs); 204 } 205 206 // CHECK_EQ(numFramesPlayed & (1 << 31), 0); // can't be negative until 12.4 hrs, test 207 // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours. 208 int64_t durationUs = (int64_t)((int32_t)numFramesPlayed * 1000000LL / mSampleRateHz) 209 + nowUs - numFramesPlayedAtUs; 210 if (durationUs < 0) { 211 // Occurs when numFramesPlayed position is very small and the following: 212 // (1) In case 1, the time nowUs is computed before getTimestamp() is called and 213 // numFramesPlayedAtUs is greater than nowUs by time more than numFramesPlayed. 214 // (2) In case 3, using getPosition and adding mAudioSink->latency() to 215 // numFramesPlayedAtUs, by a time amount greater than numFramesPlayed. 216 // 217 // Both of these are transitory conditions. 218 ALOGV("getPlayedOutDurationUs: negative duration %lld set to zero", (long long)durationUs); 219 durationUs = 0; 220 } 221 ALOGV("getPlayedOutDurationUs(%lld) nowUs(%lld) frames(%u) framesAt(%lld)", 222 (long long)durationUs, (long long)nowUs, 223 numFramesPlayed, (long long)numFramesPlayedAtUs); 224 return durationUs; 225 } 226 227 status_t MediaPlayer2AudioOutput::getFramesWritten(uint32_t *frameswritten) const { 228 Mutex::Autolock lock(mLock); 229 if (mJAudioTrack == nullptr) { 230 return NO_INIT; 231 } 232 ExtendedTimestamp ets; 233 status_t status = mJAudioTrack->getTimestamp(&ets); 234 if (status == OK || status == WOULD_BLOCK) { 235 *frameswritten = (uint32_t)ets.mPosition[ExtendedTimestamp::LOCATION_CLIENT]; 236 } 237 return status; 238 } 239 240 void MediaPlayer2AudioOutput::setAudioAttributes(const jobject attributes) { 241 Mutex::Autolock lock(mLock); 242 mAttributes = (attributes == nullptr) ? nullptr : new JObjectHolder(attributes); 243 } 244 245 audio_stream_type_t MediaPlayer2AudioOutput::getAudioStreamType() const { 246 ALOGV("getAudioStreamType"); 247 Mutex::Autolock lock(mLock); 248 if (mJAudioTrack == nullptr) { 249 return AUDIO_STREAM_DEFAULT; 250 } 251 return mJAudioTrack->getAudioStreamType(); 252 } 253 254 void MediaPlayer2AudioOutput::close_l() { 255 mJAudioTrack.clear(); 256 } 257 258 status_t MediaPlayer2AudioOutput::open( 259 uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask, 260 audio_format_t format, 261 AudioCallback cb, void *cookie, 262 audio_output_flags_t flags, 263 const audio_offload_info_t *offloadInfo, 264 uint32_t suggestedFrameCount) { 265 ALOGV("open(%u, %d, 0x%x, 0x%x, %d 0x%x)", sampleRate, channelCount, channelMask, 266 format, mSessionId, flags); 267 268 // offloading is only supported in callback mode for now. 269 // offloadInfo must be present if offload flag is set 270 if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) && 271 ((cb == nullptr) || (offloadInfo == nullptr))) { 272 return BAD_VALUE; 273 } 274 275 // compute frame count for the AudioTrack internal buffer 276 const size_t frameCount = 277 ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) ? 0 : suggestedFrameCount; 278 279 if (channelMask == CHANNEL_MASK_USE_CHANNEL_ORDER) { 280 channelMask = audio_channel_out_mask_from_count(channelCount); 281 if (0 == channelMask) { 282 ALOGE("open() error, can\'t derive mask for %d audio channels", channelCount); 283 return NO_INIT; 284 } 285 } 286 287 Mutex::Autolock lock(mLock); 288 mCallback = cb; 289 mCallbackCookie = cookie; 290 291 sp<JAudioTrack> jT; 292 CallbackData *newcbd = nullptr; 293 294 ALOGV("creating new JAudioTrack"); 295 296 if (mCallback != nullptr) { 297 newcbd = new CallbackData(this); 298 jT = new JAudioTrack( 299 sampleRate, 300 format, 301 channelMask, 302 CallbackWrapper, 303 newcbd, 304 frameCount, 305 mSessionId, 306 mAttributes != nullptr ? mAttributes->getJObject() : nullptr, 307 1.0f); // default value for maxRequiredSpeed 308 } else { 309 // TODO: Due to buffer memory concerns, we use a max target playback speed 310 // based on mPlaybackRate at the time of open (instead of kMaxRequiredSpeed), 311 // also clamping the target speed to 1.0 <= targetSpeed <= kMaxRequiredSpeed. 312 const float targetSpeed = 313 std::min(std::max(mPlaybackRate.mSpeed, 1.0f), kMaxRequiredSpeed); 314 ALOGW_IF(targetSpeed != mPlaybackRate.mSpeed, 315 "track target speed:%f clamped from playback speed:%f", 316 targetSpeed, mPlaybackRate.mSpeed); 317 jT = new JAudioTrack( 318 sampleRate, 319 format, 320 channelMask, 321 nullptr, 322 nullptr, 323 frameCount, 324 mSessionId, 325 mAttributes != nullptr ? mAttributes->getJObject() : nullptr, 326 targetSpeed); 327 } 328 329 if (jT == 0) { 330 ALOGE("Unable to create audio track"); 331 delete newcbd; 332 // t goes out of scope, so reference count drops to zero 333 return NO_INIT; 334 } 335 336 CHECK((jT != nullptr) && ((mCallback == nullptr) || (newcbd != nullptr))); 337 338 mCallbackData = newcbd; 339 ALOGV("setVolume"); 340 jT->setVolume(mVolume); 341 342 mSampleRateHz = sampleRate; 343 mFlags = flags; 344 mMsecsPerFrame = 1E3f / (mPlaybackRate.mSpeed * sampleRate); 345 mFrameSize = jT->frameSize(); 346 mJAudioTrack = jT; 347 348 return updateTrack_l(); 349 } 350 351 status_t MediaPlayer2AudioOutput::updateTrack_l() { 352 if (mJAudioTrack == nullptr) { 353 return NO_ERROR; 354 } 355 356 status_t res = NO_ERROR; 357 // Note some output devices may give us a direct track even though we don't specify it. 358 // Example: Line application b/17459982. 359 if ((mJAudioTrack->getFlags() 360 & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT)) == 0) { 361 res = mJAudioTrack->setPlaybackRate(mPlaybackRate); 362 if (res == NO_ERROR) { 363 mJAudioTrack->setAuxEffectSendLevel(mSendLevel); 364 res = mJAudioTrack->attachAuxEffect(mAuxEffectId); 365 } 366 } 367 if (mPreferredDevice != nullptr) { 368 mJAudioTrack->setPreferredDevice(mPreferredDevice->getJObject()); 369 } 370 371 mJAudioTrack->registerRoutingDelegates(mRoutingDelegates); 372 373 ALOGV("updateTrack_l() DONE status %d", res); 374 return res; 375 } 376 377 status_t MediaPlayer2AudioOutput::start() { 378 ALOGV("start"); 379 Mutex::Autolock lock(mLock); 380 if (mCallbackData != nullptr) { 381 mCallbackData->endTrackSwitch(); 382 } 383 if (mJAudioTrack != nullptr) { 384 mJAudioTrack->setVolume(mVolume); 385 mJAudioTrack->setAuxEffectSendLevel(mSendLevel); 386 status_t status = mJAudioTrack->start(); 387 return status; 388 } 389 return NO_INIT; 390 } 391 392 ssize_t MediaPlayer2AudioOutput::write(const void* buffer, size_t size, bool blocking) { 393 Mutex::Autolock lock(mLock); 394 LOG_ALWAYS_FATAL_IF(mCallback != nullptr, "Don't call write if supplying a callback."); 395 396 //ALOGV("write(%p, %u)", buffer, size); 397 if (mJAudioTrack != nullptr) { 398 return mJAudioTrack->write(buffer, size, blocking); 399 } 400 return NO_INIT; 401 } 402 403 void MediaPlayer2AudioOutput::stop() { 404 ALOGV("stop"); 405 Mutex::Autolock lock(mLock); 406 if (mJAudioTrack != nullptr) { 407 mJAudioTrack->stop(); 408 } 409 } 410 411 void MediaPlayer2AudioOutput::flush() { 412 ALOGV("flush"); 413 Mutex::Autolock lock(mLock); 414 if (mJAudioTrack != nullptr) { 415 mJAudioTrack->flush(); 416 } 417 } 418 419 void MediaPlayer2AudioOutput::pause() { 420 ALOGV("pause"); 421 Mutex::Autolock lock(mLock); 422 if (mJAudioTrack != nullptr) { 423 mJAudioTrack->pause(); 424 } 425 } 426 427 void MediaPlayer2AudioOutput::close() { 428 ALOGV("close"); 429 sp<JAudioTrack> track; 430 { 431 Mutex::Autolock lock(mLock); 432 track = mJAudioTrack; 433 close_l(); // clears mJAudioTrack 434 } 435 // destruction of the track occurs outside of mutex. 436 } 437 438 void MediaPlayer2AudioOutput::setVolume(float volume) { 439 ALOGV("setVolume(%f)", volume); 440 Mutex::Autolock lock(mLock); 441 mVolume = volume; 442 if (mJAudioTrack != nullptr) { 443 mJAudioTrack->setVolume(volume); 444 } 445 } 446 447 status_t MediaPlayer2AudioOutput::setPlaybackRate(const AudioPlaybackRate &rate) { 448 ALOGV("setPlaybackRate(%f %f %d %d)", 449 rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode); 450 Mutex::Autolock lock(mLock); 451 if (mJAudioTrack == 0) { 452 // remember rate so that we can set it when the track is opened 453 mPlaybackRate = rate; 454 return OK; 455 } 456 status_t res = mJAudioTrack->setPlaybackRate(rate); 457 if (res != NO_ERROR) { 458 return res; 459 } 460 // rate.mSpeed is always greater than 0 if setPlaybackRate succeeded 461 CHECK_GT(rate.mSpeed, 0.f); 462 mPlaybackRate = rate; 463 if (mSampleRateHz != 0) { 464 mMsecsPerFrame = 1E3f / (rate.mSpeed * mSampleRateHz); 465 } 466 return res; 467 } 468 469 status_t MediaPlayer2AudioOutput::getPlaybackRate(AudioPlaybackRate *rate) { 470 ALOGV("getPlaybackRate"); 471 Mutex::Autolock lock(mLock); 472 if (mJAudioTrack == 0) { 473 return NO_INIT; 474 } 475 *rate = mJAudioTrack->getPlaybackRate(); 476 return NO_ERROR; 477 } 478 479 status_t MediaPlayer2AudioOutput::setAuxEffectSendLevel(float level) { 480 ALOGV("setAuxEffectSendLevel(%f)", level); 481 Mutex::Autolock lock(mLock); 482 mSendLevel = level; 483 if (mJAudioTrack != nullptr) { 484 return mJAudioTrack->setAuxEffectSendLevel(level); 485 } 486 return NO_ERROR; 487 } 488 489 status_t MediaPlayer2AudioOutput::attachAuxEffect(int effectId) { 490 ALOGV("attachAuxEffect(%d)", effectId); 491 Mutex::Autolock lock(mLock); 492 mAuxEffectId = effectId; 493 if (mJAudioTrack != nullptr) { 494 return mJAudioTrack->attachAuxEffect(effectId); 495 } 496 return NO_ERROR; 497 } 498 499 status_t MediaPlayer2AudioOutput::setPreferredDevice(jobject device) { 500 ALOGV("setPreferredDevice"); 501 Mutex::Autolock lock(mLock); 502 status_t ret = NO_ERROR; 503 if (mJAudioTrack != nullptr) { 504 ret = mJAudioTrack->setPreferredDevice(device); 505 } 506 if (ret == NO_ERROR) { 507 mPreferredDevice = new JObjectHolder(device); 508 } 509 return ret; 510 } 511 512 jobject MediaPlayer2AudioOutput::getRoutedDevice() { 513 ALOGV("getRoutedDevice"); 514 Mutex::Autolock lock(mLock); 515 if (mJAudioTrack != nullptr) { 516 return mJAudioTrack->getRoutedDevice(); 517 } 518 return nullptr; 519 } 520 521 status_t MediaPlayer2AudioOutput::addAudioDeviceCallback(jobject jRoutingDelegate) { 522 ALOGV("addAudioDeviceCallback"); 523 Mutex::Autolock lock(mLock); 524 jobject listener = JAudioTrack::getListener(jRoutingDelegate); 525 if (JAudioTrack::findByKey(mRoutingDelegates, listener) == nullptr) { 526 sp<JObjectHolder> listenerHolder = new JObjectHolder(listener); 527 jobject handler = JAudioTrack::getHandler(jRoutingDelegate); 528 sp<JObjectHolder> routingDelegateHolder = new JObjectHolder(jRoutingDelegate); 529 530 mRoutingDelegates.push_back(std::pair<sp<JObjectHolder>, sp<JObjectHolder>>( 531 listenerHolder, routingDelegateHolder)); 532 533 if (mJAudioTrack != nullptr) { 534 return mJAudioTrack->addAudioDeviceCallback( 535 routingDelegateHolder->getJObject(), handler); 536 } 537 } 538 return NO_ERROR; 539 } 540 541 status_t MediaPlayer2AudioOutput::removeAudioDeviceCallback(jobject listener) { 542 ALOGV("removeAudioDeviceCallback"); 543 Mutex::Autolock lock(mLock); 544 jobject routingDelegate = nullptr; 545 if ((routingDelegate = JAudioTrack::findByKey(mRoutingDelegates, listener)) != nullptr) { 546 if (mJAudioTrack != nullptr) { 547 mJAudioTrack->removeAudioDeviceCallback(routingDelegate); 548 } 549 JAudioTrack::eraseByKey(mRoutingDelegates, listener); 550 } 551 return NO_ERROR; 552 } 553 554 // static 555 void MediaPlayer2AudioOutput::CallbackWrapper( 556 int event, void *cookie, void *info) { 557 //ALOGV("callbackwrapper"); 558 CallbackData *data = (CallbackData*)cookie; 559 // lock to ensure we aren't caught in the middle of a track switch. 560 data->lock(); 561 MediaPlayer2AudioOutput *me = data->getOutput(); 562 JAudioTrack::Buffer *buffer = (JAudioTrack::Buffer *)info; 563 if (me == nullptr) { 564 // no output set, likely because the track was scheduled to be reused 565 // by another player, but the format turned out to be incompatible. 566 data->unlock(); 567 if (buffer != nullptr) { 568 buffer->mSize = 0; 569 } 570 return; 571 } 572 573 switch(event) { 574 case JAudioTrack::EVENT_MORE_DATA: { 575 size_t actualSize = (*me->mCallback)( 576 me, buffer->mData, buffer->mSize, me->mCallbackCookie, 577 CB_EVENT_FILL_BUFFER); 578 579 // Log when no data is returned from the callback. 580 // (1) We may have no data (especially with network streaming sources). 581 // (2) We may have reached the EOS and the audio track is not stopped yet. 582 // Note that AwesomePlayer/AudioPlayer will only return zero size when it reaches the EOS. 583 // NuPlayer2Renderer will return zero when it doesn't have data (it doesn't block to fill). 584 // 585 // This is a benign busy-wait, with the next data request generated 10 ms or more later; 586 // nevertheless for power reasons, we don't want to see too many of these. 587 588 ALOGV_IF(actualSize == 0 && buffer->mSize > 0, "callbackwrapper: empty buffer returned"); 589 590 buffer->mSize = actualSize; 591 } break; 592 593 case JAudioTrack::EVENT_STREAM_END: 594 // currently only occurs for offloaded callbacks 595 ALOGV("callbackwrapper: deliver EVENT_STREAM_END"); 596 (*me->mCallback)(me, nullptr /* buffer */, 0 /* size */, 597 me->mCallbackCookie, CB_EVENT_STREAM_END); 598 break; 599 600 case JAudioTrack::EVENT_NEW_IAUDIOTRACK : 601 ALOGV("callbackwrapper: deliver EVENT_TEAR_DOWN"); 602 (*me->mCallback)(me, nullptr /* buffer */, 0 /* size */, 603 me->mCallbackCookie, CB_EVENT_TEAR_DOWN); 604 break; 605 606 case JAudioTrack::EVENT_UNDERRUN: 607 // This occurs when there is no data available, typically 608 // when there is a failure to supply data to the AudioTrack. It can also 609 // occur in non-offloaded mode when the audio device comes out of standby. 610 // 611 // If an AudioTrack underruns it outputs silence. Since this happens suddenly 612 // it may sound like an audible pop or glitch. 613 // 614 // The underrun event is sent once per track underrun; the condition is reset 615 // when more data is sent to the AudioTrack. 616 ALOGD("callbackwrapper: EVENT_UNDERRUN (discarded)"); 617 break; 618 619 default: 620 ALOGE("received unknown event type: %d inside CallbackWrapper !", event); 621 } 622 623 data->unlock(); 624 } 625 626 int32_t MediaPlayer2AudioOutput::getSessionId() const { 627 Mutex::Autolock lock(mLock); 628 return mSessionId; 629 } 630 631 void MediaPlayer2AudioOutput::setSessionId(const int32_t sessionId) { 632 Mutex::Autolock lock(mLock); 633 mSessionId = sessionId; 634 } 635 636 uint32_t MediaPlayer2AudioOutput::getSampleRate() const { 637 Mutex::Autolock lock(mLock); 638 if (mJAudioTrack == 0) { 639 return 0; 640 } 641 return mJAudioTrack->getSampleRate(); 642 } 643 644 int64_t MediaPlayer2AudioOutput::getBufferDurationInUs() const { 645 Mutex::Autolock lock(mLock); 646 if (mJAudioTrack == 0) { 647 return 0; 648 } 649 int64_t duration; 650 if (mJAudioTrack->getBufferDurationInUs(&duration) != OK) { 651 return 0; 652 } 653 return duration; 654 } 655 656 } // namespace android 657