AwesomePlayer.cpp revision a657f8deaf21acbe5faba7be1df9c6681d44d471
1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17//#define LOG_NDEBUG 0 18#define LOG_TAG "AwesomePlayer" 19#include <utils/Log.h> 20 21#include "include/AwesomePlayer.h" 22#include "include/Prefetcher.h" 23#include "include/SoftwareRenderer.h" 24 25#include <binder/IPCThreadState.h> 26#include <media/stagefright/AudioPlayer.h> 27#include <media/stagefright/DataSource.h> 28#include <media/stagefright/FileSource.h> 29#include <media/stagefright/MediaBuffer.h> 30#include <media/stagefright/MediaDefs.h> 31#include <media/stagefright/MediaExtractor.h> 32#include <media/stagefright/MediaDebug.h> 33#include <media/stagefright/MediaSource.h> 34#include <media/stagefright/MetaData.h> 35#include <media/stagefright/OMXCodec.h> 36 37namespace android { 38 39struct AwesomeEvent : public TimedEventQueue::Event { 40 AwesomeEvent(AwesomePlayer *player, int32_t code) 41 : mPlayer(player), 42 mCode(code) { 43 } 44 45protected: 46 virtual ~AwesomeEvent() {} 47 48 virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) { 49 mPlayer->onEvent(mCode); 50 } 51 52private: 53 AwesomePlayer *mPlayer; 54 int32_t mCode; 55 56 AwesomeEvent(const AwesomeEvent &); 57 AwesomeEvent &operator=(const AwesomeEvent &); 58}; 59 60struct AwesomeRemoteRenderer : public AwesomeRenderer { 61 AwesomeRemoteRenderer(const sp<IOMXRenderer> &target) 62 : mTarget(target) { 63 } 64 65 virtual void render(MediaBuffer *buffer) { 66 void *id; 67 if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) { 68 mTarget->render((IOMX::buffer_id)id); 69 } 70 } 71 72private: 73 sp<IOMXRenderer> mTarget; 74 75 AwesomeRemoteRenderer(const AwesomeRemoteRenderer &); 76 AwesomeRemoteRenderer &operator=(const AwesomeRemoteRenderer &); 77}; 78 79struct AwesomeLocalRenderer : public AwesomeRenderer { 80 AwesomeLocalRenderer( 81 OMX_COLOR_FORMATTYPE colorFormat, 82 const sp<ISurface> &surface, 83 size_t displayWidth, size_t displayHeight, 84 size_t decodedWidth, size_t decodedHeight) 85 : mTarget(new SoftwareRenderer( 86 colorFormat, surface, displayWidth, displayHeight, 87 decodedWidth, decodedHeight)) { 88 } 89 90 virtual void render(MediaBuffer *buffer) { 91 mTarget->render( 92 (const uint8_t *)buffer->data() + buffer->range_offset(), 93 buffer->range_length(), NULL); 94 } 95 96protected: 97 virtual ~AwesomeLocalRenderer() { 98 delete mTarget; 99 mTarget = NULL; 100 } 101 102private: 103 SoftwareRenderer *mTarget; 104 105 AwesomeLocalRenderer(const AwesomeLocalRenderer &); 106 AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);; 107}; 108 109AwesomePlayer::AwesomePlayer() 110 : mTimeSource(NULL), 111 mAudioPlayer(NULL), 112 mLastVideoBuffer(NULL), 113 mVideoBuffer(NULL) { 114 CHECK_EQ(mClient.connect(), OK); 115 116 DataSource::RegisterDefaultSniffers(); 117 118 mVideoEvent = new AwesomeEvent(this, 0); 119 mVideoEventPending = false; 120 mStreamDoneEvent = new AwesomeEvent(this, 1); 121 mStreamDoneEventPending = false; 122 mBufferingEvent = new AwesomeEvent(this, 2); 123 mBufferingEventPending = false; 124 mCheckAudioStatusEvent = new AwesomeEvent(this, 3); 125 mAudioStatusEventPending = false; 126 127 mQueue.start(); 128 129 reset(); 130} 131 132AwesomePlayer::~AwesomePlayer() { 133 mQueue.stop(); 134 135 reset(); 136 137 mClient.disconnect(); 138} 139 140void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) { 141 mQueue.cancelEvent(mVideoEvent->eventID()); 142 mVideoEventPending = false; 143 mQueue.cancelEvent(mStreamDoneEvent->eventID()); 144 mStreamDoneEventPending = false; 145 mQueue.cancelEvent(mCheckAudioStatusEvent->eventID()); 146 mAudioStatusEventPending = false; 147 148 if (!keepBufferingGoing) { 149 mQueue.cancelEvent(mBufferingEvent->eventID()); 150 mBufferingEventPending = false; 151 } 152} 153 154void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) { 155 Mutex::Autolock autoLock(mLock); 156 mListener = listener; 157} 158 159status_t AwesomePlayer::setDataSource( 160 const char *uri, const KeyedVector<String8, String8> *headers) { 161 Mutex::Autolock autoLock(mLock); 162 163 reset_l(); 164 165 sp<DataSource> dataSource = DataSource::CreateFromURI(uri, headers); 166 167 if (dataSource == NULL) { 168 return UNKNOWN_ERROR; 169 } 170 171 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); 172 173 if (extractor == NULL) { 174 return UNKNOWN_ERROR; 175 } 176 177 if (dataSource->flags() & DataSource::kWantsPrefetching) { 178 mPrefetcher = new Prefetcher; 179 } 180 181 return setDataSource_l(extractor); 182} 183 184status_t AwesomePlayer::setDataSource( 185 int fd, int64_t offset, int64_t length) { 186 Mutex::Autolock autoLock(mLock); 187 188 reset_l(); 189 190 sp<DataSource> source = new FileSource(fd, offset, length); 191 192 status_t err = source->initCheck(); 193 194 if (err != OK) { 195 return err; 196 } 197 198 sp<MediaExtractor> extractor = MediaExtractor::Create(source); 199 200 if (extractor == NULL) { 201 return UNKNOWN_ERROR; 202 } 203 204 return setDataSource_l(extractor); 205} 206 207status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) { 208 bool haveAudio = false; 209 bool haveVideo = false; 210 for (size_t i = 0; i < extractor->countTracks(); ++i) { 211 sp<MetaData> meta = extractor->getTrackMetaData(i); 212 213 const char *mime; 214 CHECK(meta->findCString(kKeyMIMEType, &mime)); 215 216 if (!haveVideo && !strncasecmp(mime, "video/", 6)) { 217 if (setVideoSource(extractor->getTrack(i)) == OK) { 218 haveVideo = true; 219 } 220 } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) { 221 if (setAudioSource(extractor->getTrack(i)) == OK) { 222 haveAudio = true; 223 } 224 } 225 226 if (haveAudio && haveVideo) { 227 break; 228 } 229 } 230 231 return !haveAudio && !haveVideo ? UNKNOWN_ERROR : OK; 232} 233 234void AwesomePlayer::reset() { 235 Mutex::Autolock autoLock(mLock); 236 reset_l(); 237} 238 239void AwesomePlayer::reset_l() { 240 cancelPlayerEvents(); 241 242 mVideoRenderer.clear(); 243 244 if (mLastVideoBuffer) { 245 mLastVideoBuffer->release(); 246 mLastVideoBuffer = NULL; 247 } 248 249 if (mVideoBuffer) { 250 mVideoBuffer->release(); 251 mVideoBuffer = NULL; 252 } 253 254 if (mVideoSource != NULL) { 255 mVideoSource->stop(); 256 257 // The following hack is necessary to ensure that the OMX 258 // component is completely released by the time we may try 259 // to instantiate it again. 260 wp<MediaSource> tmp = mVideoSource; 261 mVideoSource.clear(); 262 while (tmp.promote() != NULL) { 263 usleep(1000); 264 } 265 IPCThreadState::self()->flushCommands(); 266 } 267 268 mAudioSource.clear(); 269 270 if (mTimeSource != mAudioPlayer) { 271 delete mTimeSource; 272 } 273 mTimeSource = NULL; 274 275 delete mAudioPlayer; 276 mAudioPlayer = NULL; 277 278 mDurationUs = -1; 279 mFlags = 0; 280 mVideoWidth = mVideoHeight = -1; 281 mTimeSourceDeltaUs = 0; 282 mVideoTimeUs = 0; 283 284 mSeeking = false; 285 mSeekTimeUs = 0; 286 287 mPrefetcher.clear(); 288} 289 290void AwesomePlayer::notifyListener_l(int msg, int ext1) { 291 if (mListener != NULL) { 292 sp<MediaPlayerBase> listener = mListener.promote(); 293 294 if (listener != NULL) { 295 listener->sendEvent(msg, ext1); 296 } 297 } 298} 299 300void AwesomePlayer::onBufferingUpdate() { 301 Mutex::Autolock autoLock(mLock); 302 mBufferingEventPending = false; 303 304 if (mDurationUs >= 0) { 305 int64_t cachedDurationUs = mPrefetcher->getCachedDurationUs(); 306 int64_t positionUs = 0; 307 if (mVideoSource != NULL) { 308 positionUs = mVideoTimeUs; 309 } else if (mAudioPlayer != NULL) { 310 positionUs = mAudioPlayer->getMediaTimeUs(); 311 } 312 313 cachedDurationUs += positionUs; 314 315 double percentage = (double)cachedDurationUs / mDurationUs; 316 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage * 100.0); 317 318 postBufferingEvent_l(); 319 } 320} 321 322void AwesomePlayer::onStreamDone() { 323 // Posted whenever any stream finishes playing. 324 325 Mutex::Autolock autoLock(mLock); 326 mStreamDoneEventPending = false; 327 328 if (mFlags & LOOPING) { 329 seekTo_l(0); 330 331 if (mVideoSource != NULL) { 332 postVideoEvent_l(); 333 } 334 } else { 335 notifyListener_l(MEDIA_PLAYBACK_COMPLETE); 336 337 pause_l(); 338 } 339} 340 341status_t AwesomePlayer::play() { 342 Mutex::Autolock autoLock(mLock); 343 344 if (mFlags & PLAYING) { 345 return OK; 346 } 347 348 mFlags |= PLAYING; 349 mFlags |= FIRST_FRAME; 350 351 bool deferredAudioSeek = false; 352 353 if (mAudioSource != NULL) { 354 if (mAudioPlayer == NULL) { 355 if (mAudioSink != NULL) { 356 mAudioPlayer = new AudioPlayer(mAudioSink); 357 mAudioPlayer->setSource(mAudioSource); 358 status_t err = mAudioPlayer->start(); 359 360 if (err != OK) { 361 delete mAudioPlayer; 362 mAudioPlayer = NULL; 363 364 mFlags &= ~(PLAYING | FIRST_FRAME); 365 366 return err; 367 } 368 369 delete mTimeSource; 370 mTimeSource = mAudioPlayer; 371 372 deferredAudioSeek = true; 373 374 mWatchForAudioSeekComplete = false; 375 mWatchForAudioEOS = true; 376 } 377 } else { 378 mAudioPlayer->resume(); 379 } 380 381 postCheckAudioStatusEvent_l(); 382 } 383 384 if (mTimeSource == NULL && mAudioPlayer == NULL) { 385 mTimeSource = new SystemTimeSource; 386 } 387 388 if (mVideoSource != NULL) { 389 // Kick off video playback 390 postVideoEvent_l(); 391 } 392 393 if (deferredAudioSeek) { 394 // If there was a seek request while we were paused 395 // and we're just starting up again, honor the request now. 396 seekAudioIfNecessary_l(); 397 } 398 399 postBufferingEvent_l(); 400 401 return OK; 402} 403 404void AwesomePlayer::initRenderer_l() { 405 if (mISurface != NULL) { 406 sp<MetaData> meta = mVideoSource->getFormat(); 407 408 int32_t format; 409 const char *component; 410 int32_t decodedWidth, decodedHeight; 411 CHECK(meta->findInt32(kKeyColorFormat, &format)); 412 CHECK(meta->findCString(kKeyDecoderComponent, &component)); 413 CHECK(meta->findInt32(kKeyWidth, &decodedWidth)); 414 CHECK(meta->findInt32(kKeyHeight, &decodedHeight)); 415 416 mVideoRenderer.clear(); 417 418 // Must ensure that mVideoRenderer's destructor is actually executed 419 // before creating a new one. 420 IPCThreadState::self()->flushCommands(); 421 422 if (!strncmp("OMX.", component, 4)) { 423 // Our OMX codecs allocate buffers on the media_server side 424 // therefore they require a remote IOMXRenderer that knows how 425 // to display them. 426 mVideoRenderer = new AwesomeRemoteRenderer( 427 mClient.interface()->createRenderer( 428 mISurface, component, 429 (OMX_COLOR_FORMATTYPE)format, 430 decodedWidth, decodedHeight, 431 mVideoWidth, mVideoHeight)); 432 } else { 433 // Other decoders are instantiated locally and as a consequence 434 // allocate their buffers in local address space. 435 mVideoRenderer = new AwesomeLocalRenderer( 436 (OMX_COLOR_FORMATTYPE)format, 437 mISurface, 438 mVideoWidth, mVideoHeight, 439 decodedWidth, decodedHeight); 440 } 441 } 442} 443 444status_t AwesomePlayer::pause() { 445 Mutex::Autolock autoLock(mLock); 446 return pause_l(); 447} 448 449status_t AwesomePlayer::pause_l() { 450 if (!(mFlags & PLAYING)) { 451 return OK; 452 } 453 454 cancelPlayerEvents(true /* keepBufferingGoing */); 455 456 if (mAudioPlayer != NULL) { 457 mAudioPlayer->pause(); 458 } 459 460 mFlags &= ~PLAYING; 461 462 return OK; 463} 464 465bool AwesomePlayer::isPlaying() const { 466 Mutex::Autolock autoLock(mLock); 467 468 return mFlags & PLAYING; 469} 470 471void AwesomePlayer::setISurface(const sp<ISurface> &isurface) { 472 Mutex::Autolock autoLock(mLock); 473 474 mISurface = isurface; 475} 476 477void AwesomePlayer::setAudioSink( 478 const sp<MediaPlayerBase::AudioSink> &audioSink) { 479 Mutex::Autolock autoLock(mLock); 480 481 mAudioSink = audioSink; 482} 483 484status_t AwesomePlayer::setLooping(bool shouldLoop) { 485 Mutex::Autolock autoLock(mLock); 486 487 mFlags = mFlags & ~LOOPING; 488 489 if (shouldLoop) { 490 mFlags |= LOOPING; 491 } 492 493 return OK; 494} 495 496status_t AwesomePlayer::getDuration(int64_t *durationUs) { 497 Mutex::Autolock autoLock(mLock); 498 499 if (mDurationUs < 0) { 500 return UNKNOWN_ERROR; 501 } 502 503 *durationUs = mDurationUs; 504 505 return OK; 506} 507 508status_t AwesomePlayer::getPosition(int64_t *positionUs) { 509 Mutex::Autolock autoLock(mLock); 510 511 if (mVideoSource != NULL) { 512 *positionUs = mVideoTimeUs; 513 } else if (mAudioPlayer != NULL) { 514 *positionUs = mAudioPlayer->getMediaTimeUs(); 515 } else { 516 *positionUs = 0; 517 } 518 519 return OK; 520} 521 522status_t AwesomePlayer::seekTo(int64_t timeUs) { 523 Mutex::Autolock autoLock(mLock); 524 return seekTo_l(timeUs); 525} 526 527status_t AwesomePlayer::seekTo_l(int64_t timeUs) { 528 mSeeking = true; 529 mSeekTimeUs = timeUs; 530 531 seekAudioIfNecessary_l(); 532 533 return OK; 534} 535 536void AwesomePlayer::seekAudioIfNecessary_l() { 537 if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) { 538 mAudioPlayer->seekTo(mSeekTimeUs); 539 540 mWatchForAudioSeekComplete = true; 541 mWatchForAudioEOS = true; 542 mSeeking = false; 543 } 544} 545 546status_t AwesomePlayer::getVideoDimensions( 547 int32_t *width, int32_t *height) const { 548 Mutex::Autolock autoLock(mLock); 549 550 if (mVideoWidth < 0 || mVideoHeight < 0) { 551 return UNKNOWN_ERROR; 552 } 553 554 *width = mVideoWidth; 555 *height = mVideoHeight; 556 557 return OK; 558} 559 560status_t AwesomePlayer::setAudioSource(sp<MediaSource> source) { 561 if (source == NULL) { 562 return UNKNOWN_ERROR; 563 } 564 565 if (mPrefetcher != NULL) { 566 source = mPrefetcher->addSource(source); 567 } 568 569 sp<MetaData> meta = source->getFormat(); 570 571 const char *mime; 572 CHECK(meta->findCString(kKeyMIMEType, &mime)); 573 574 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) { 575 mAudioSource = source; 576 } else { 577 mAudioSource = OMXCodec::Create( 578 mClient.interface(), source->getFormat(), 579 false, // createEncoder 580 source); 581 } 582 583 if (mAudioSource != NULL) { 584 int64_t durationUs; 585 if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) { 586 if (mDurationUs < 0 || durationUs > mDurationUs) { 587 mDurationUs = durationUs; 588 } 589 } 590 } 591 592 return mAudioSource != NULL ? OK : UNKNOWN_ERROR; 593} 594 595status_t AwesomePlayer::setVideoSource(sp<MediaSource> source) { 596 if (source == NULL) { 597 return UNKNOWN_ERROR; 598 } 599 600 if (mPrefetcher != NULL) { 601 source = mPrefetcher->addSource(source); 602 } 603 604 mVideoSource = OMXCodec::Create( 605 mClient.interface(), source->getFormat(), 606 false, // createEncoder 607 source); 608 609 if (mVideoSource != NULL) { 610 int64_t durationUs; 611 if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) { 612 if (mDurationUs < 0 || durationUs > mDurationUs) { 613 mDurationUs = durationUs; 614 } 615 } 616 617 CHECK(source->getFormat()->findInt32(kKeyWidth, &mVideoWidth)); 618 CHECK(source->getFormat()->findInt32(kKeyHeight, &mVideoHeight)); 619 620 mVideoSource->start(); 621 } 622 623 return mVideoSource != NULL ? OK : UNKNOWN_ERROR; 624} 625 626void AwesomePlayer::onEvent(int32_t code) { 627 if (code == 1) { 628 onStreamDone(); 629 return; 630 } else if (code == 2) { 631 onBufferingUpdate(); 632 return; 633 } else if (code == 3) { 634 onCheckAudioStatus(); 635 return; 636 } 637 638 Mutex::Autolock autoLock(mLock); 639 640 mVideoEventPending = false; 641 642 if (mSeeking) { 643 if (mLastVideoBuffer) { 644 mLastVideoBuffer->release(); 645 mLastVideoBuffer = NULL; 646 } 647 648 if (mVideoBuffer) { 649 mVideoBuffer->release(); 650 mVideoBuffer = NULL; 651 } 652 } 653 654 if (!mVideoBuffer) { 655 MediaSource::ReadOptions options; 656 if (mSeeking) { 657 LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6); 658 659 options.setSeekTo(mSeekTimeUs); 660 } 661 for (;;) { 662 status_t err = mVideoSource->read(&mVideoBuffer, &options); 663 options.clearSeekTo(); 664 665 if (err != OK) { 666 CHECK_EQ(mVideoBuffer, NULL); 667 668 if (err == INFO_FORMAT_CHANGED) { 669 LOGV("VideoSource signalled format change."); 670 671 if (mVideoRenderer != NULL) { 672 initRenderer_l(); 673 } 674 continue; 675 } 676 677 postStreamDoneEvent_l(); 678 return; 679 } 680 681 if (mVideoBuffer->range_length() == 0) { 682 // Some decoders, notably the PV AVC software decoder 683 // return spurious empty buffers that we just want to ignore. 684 685 mVideoBuffer->release(); 686 mVideoBuffer = NULL; 687 continue; 688 } 689 690 break; 691 } 692 } 693 694 int64_t timeUs; 695 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs)); 696 697 mVideoTimeUs = timeUs; 698 699 if (mSeeking) { 700 if (mAudioPlayer != NULL) { 701 LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6); 702 703 mAudioPlayer->seekTo(timeUs); 704 mWatchForAudioSeekComplete = true; 705 mWatchForAudioEOS = true; 706 } else { 707 // If we're playing video only, report seek complete now, 708 // otherwise audio player will notify us later. 709 notifyListener_l(MEDIA_SEEK_COMPLETE); 710 } 711 712 mFlags |= FIRST_FRAME; 713 mSeeking = false; 714 } 715 716 if (mFlags & FIRST_FRAME) { 717 mFlags &= ~FIRST_FRAME; 718 719 mTimeSourceDeltaUs = mTimeSource->getRealTimeUs() - timeUs; 720 } 721 722 int64_t realTimeUs, mediaTimeUs; 723 if (mAudioPlayer != NULL 724 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) { 725 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs; 726 } 727 728 int64_t nowUs = mTimeSource->getRealTimeUs() - mTimeSourceDeltaUs; 729 730 int64_t latenessUs = nowUs - timeUs; 731 732 if (latenessUs > 40000) { 733 // We're more than 40ms late. 734 LOGI("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6); 735 736 mVideoBuffer->release(); 737 mVideoBuffer = NULL; 738 739 postVideoEvent_l(); 740 return; 741 } 742 743 if (latenessUs < -10000) { 744 // We're more than 10ms early. 745 746 postVideoEvent_l(10000); 747 return; 748 } 749 750 if (mVideoRenderer == NULL) { 751 initRenderer_l(); 752 } 753 754 if (mVideoRenderer != NULL) { 755 mVideoRenderer->render(mVideoBuffer); 756 } 757 758 if (mLastVideoBuffer) { 759 mLastVideoBuffer->release(); 760 mLastVideoBuffer = NULL; 761 } 762 mLastVideoBuffer = mVideoBuffer; 763 mVideoBuffer = NULL; 764 765 postVideoEvent_l(); 766} 767 768void AwesomePlayer::postVideoEvent_l(int64_t delayUs) { 769 if (mVideoEventPending) { 770 return; 771 } 772 773 mVideoEventPending = true; 774 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs); 775} 776 777void AwesomePlayer::postStreamDoneEvent_l() { 778 if (mStreamDoneEventPending) { 779 return; 780 } 781 mStreamDoneEventPending = true; 782 mQueue.postEvent(mStreamDoneEvent); 783} 784 785void AwesomePlayer::postBufferingEvent_l() { 786 if (mPrefetcher == NULL) { 787 return; 788 } 789 790 if (mBufferingEventPending) { 791 return; 792 } 793 mBufferingEventPending = true; 794 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll); 795} 796 797void AwesomePlayer::postCheckAudioStatusEvent_l() { 798 if (mAudioStatusEventPending) { 799 return; 800 } 801 mAudioStatusEventPending = true; 802 mQueue.postEventWithDelay(mCheckAudioStatusEvent, 100000ll); 803} 804 805void AwesomePlayer::onCheckAudioStatus() { 806 Mutex::Autolock autoLock(mLock); 807 mAudioStatusEventPending = false; 808 809 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) { 810 mWatchForAudioSeekComplete = false; 811 notifyListener_l(MEDIA_SEEK_COMPLETE); 812 } 813 814 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS()) { 815 mWatchForAudioEOS = false; 816 postStreamDoneEvent_l(); 817 } 818 819 postCheckAudioStatusEvent_l(); 820} 821 822} // namespace android 823 824