NuPlayerDriver.cpp revision 1de2223f43b0a6363de7d2242a8bfc9323bd64d0
1/* 2 * Copyright (C) 2010 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 "NuPlayerDriver" 19#include <inttypes.h> 20#include <utils/Log.h> 21#include <cutils/properties.h> 22 23#include "NuPlayerDriver.h" 24 25#include "NuPlayer.h" 26#include "NuPlayerSource.h" 27 28#include <media/stagefright/foundation/ADebug.h> 29#include <media/stagefright/foundation/ALooper.h> 30#include <media/stagefright/foundation/AUtils.h> 31#include <media/stagefright/MetaData.h> 32#include <media/stagefright/Utils.h> 33 34#include <media/IMediaAnalyticsService.h> 35 36static const int kDumpLockRetries = 50; 37static const int kDumpLockSleepUs = 20000; 38 39namespace android { 40 41 42NuPlayerDriver::NuPlayerDriver(pid_t pid) 43 : mState(STATE_IDLE), 44 mIsAsyncPrepare(false), 45 mAsyncResult(UNKNOWN_ERROR), 46 mSetSurfaceInProgress(false), 47 mDurationUs(-1), 48 mPositionUs(-1), 49 mSeekInProgress(false), 50 mPlayingTimeUs(0), 51 mLooper(new ALooper), 52 mPlayerFlags(0), 53 mAnalyticsItem(NULL), 54 mAtEOS(false), 55 mLooping(false), 56 mAutoLoop(false) { 57 ALOGD("NuPlayerDriver(%p) created, clientPid(%d)", this, pid); 58 mLooper->setName("NuPlayerDriver Looper"); 59 60 // set up an analytics record 61 mAnalyticsItem = new MediaAnalyticsItem("nuplayer"); 62 mAnalyticsItem->generateSessionID(); 63 64 mLooper->start( 65 false, /* runOnCallingThread */ 66 true, /* canCallJava */ 67 PRIORITY_AUDIO); 68 69 mPlayer = new NuPlayer(pid); 70 mLooper->registerHandler(mPlayer); 71 72 mPlayer->setDriver(this); 73} 74 75NuPlayerDriver::~NuPlayerDriver() { 76 ALOGV("~NuPlayerDriver(%p)", this); 77 mLooper->stop(); 78 79 // finalize any pending metrics, usually a no-op. 80 finalizeMetrics("destructor"); 81 logMetrics("destructor"); 82 83 if (mAnalyticsItem != NULL) { 84 delete mAnalyticsItem; 85 mAnalyticsItem = NULL; 86 } 87} 88 89status_t NuPlayerDriver::initCheck() { 90 return OK; 91} 92 93status_t NuPlayerDriver::setUID(uid_t uid) { 94 mPlayer->setUID(uid); 95 96 return OK; 97} 98 99status_t NuPlayerDriver::setDataSource( 100 const sp<IMediaHTTPService> &httpService, 101 const char *url, 102 const KeyedVector<String8, String8> *headers) { 103 ALOGV("setDataSource(%p) url(%s)", this, uriDebugString(url, false).c_str()); 104 Mutex::Autolock autoLock(mLock); 105 106 if (mState != STATE_IDLE) { 107 return INVALID_OPERATION; 108 } 109 110 mState = STATE_SET_DATASOURCE_PENDING; 111 112 mPlayer->setDataSourceAsync(httpService, url, headers); 113 114 while (mState == STATE_SET_DATASOURCE_PENDING) { 115 mCondition.wait(mLock); 116 } 117 118 return mAsyncResult; 119} 120 121status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) { 122 ALOGV("setDataSource(%p) file(%d)", this, fd); 123 Mutex::Autolock autoLock(mLock); 124 125 if (mState != STATE_IDLE) { 126 return INVALID_OPERATION; 127 } 128 129 mState = STATE_SET_DATASOURCE_PENDING; 130 131 mPlayer->setDataSourceAsync(fd, offset, length); 132 133 while (mState == STATE_SET_DATASOURCE_PENDING) { 134 mCondition.wait(mLock); 135 } 136 137 return mAsyncResult; 138} 139 140status_t NuPlayerDriver::setDataSource(const sp<IStreamSource> &source) { 141 ALOGV("setDataSource(%p) stream source", this); 142 Mutex::Autolock autoLock(mLock); 143 144 if (mState != STATE_IDLE) { 145 return INVALID_OPERATION; 146 } 147 148 mState = STATE_SET_DATASOURCE_PENDING; 149 150 mPlayer->setDataSourceAsync(source); 151 152 while (mState == STATE_SET_DATASOURCE_PENDING) { 153 mCondition.wait(mLock); 154 } 155 156 return mAsyncResult; 157} 158 159status_t NuPlayerDriver::setDataSource(const sp<DataSource> &source) { 160 ALOGV("setDataSource(%p) callback source", this); 161 Mutex::Autolock autoLock(mLock); 162 163 if (mState != STATE_IDLE) { 164 return INVALID_OPERATION; 165 } 166 167 mState = STATE_SET_DATASOURCE_PENDING; 168 169 mPlayer->setDataSourceAsync(source); 170 171 while (mState == STATE_SET_DATASOURCE_PENDING) { 172 mCondition.wait(mLock); 173 } 174 175 return mAsyncResult; 176} 177 178status_t NuPlayerDriver::setVideoSurfaceTexture( 179 const sp<IGraphicBufferProducer> &bufferProducer) { 180 ALOGV("setVideoSurfaceTexture(%p)", this); 181 Mutex::Autolock autoLock(mLock); 182 183 if (mSetSurfaceInProgress) { 184 return INVALID_OPERATION; 185 } 186 187 switch (mState) { 188 case STATE_SET_DATASOURCE_PENDING: 189 case STATE_RESET_IN_PROGRESS: 190 return INVALID_OPERATION; 191 192 default: 193 break; 194 } 195 196 mSetSurfaceInProgress = true; 197 198 mPlayer->setVideoSurfaceTextureAsync(bufferProducer); 199 200 while (mSetSurfaceInProgress) { 201 mCondition.wait(mLock); 202 } 203 204 return OK; 205} 206 207status_t NuPlayerDriver::prepare() { 208 ALOGV("prepare(%p)", this); 209 Mutex::Autolock autoLock(mLock); 210 return prepare_l(); 211} 212 213status_t NuPlayerDriver::prepare_l() { 214 switch (mState) { 215 case STATE_UNPREPARED: 216 mState = STATE_PREPARING; 217 218 // Make sure we're not posting any notifications, success or 219 // failure information is only communicated through our result 220 // code. 221 mIsAsyncPrepare = false; 222 mPlayer->prepareAsync(); 223 while (mState == STATE_PREPARING) { 224 mCondition.wait(mLock); 225 } 226 return (mState == STATE_PREPARED) ? OK : UNKNOWN_ERROR; 227 case STATE_STOPPED: 228 // this is really just paused. handle as seek to start 229 mAtEOS = false; 230 mState = STATE_STOPPED_AND_PREPARING; 231 mIsAsyncPrepare = false; 232 mPlayer->seekToAsync(0, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */, 233 true /* needNotify */); 234 while (mState == STATE_STOPPED_AND_PREPARING) { 235 mCondition.wait(mLock); 236 } 237 return (mState == STATE_STOPPED_AND_PREPARED) ? OK : UNKNOWN_ERROR; 238 default: 239 return INVALID_OPERATION; 240 }; 241} 242 243status_t NuPlayerDriver::prepareAsync() { 244 ALOGV("prepareAsync(%p)", this); 245 Mutex::Autolock autoLock(mLock); 246 247 switch (mState) { 248 case STATE_UNPREPARED: 249 mState = STATE_PREPARING; 250 mIsAsyncPrepare = true; 251 mPlayer->prepareAsync(); 252 return OK; 253 case STATE_STOPPED: 254 // this is really just paused. handle as seek to start 255 mAtEOS = false; 256 mState = STATE_STOPPED_AND_PREPARING; 257 mIsAsyncPrepare = true; 258 mPlayer->seekToAsync(0, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */, 259 true /* needNotify */); 260 return OK; 261 default: 262 return INVALID_OPERATION; 263 }; 264} 265 266status_t NuPlayerDriver::start() { 267 ALOGD("start(%p), state is %d, eos is %d", this, mState, mAtEOS); 268 Mutex::Autolock autoLock(mLock); 269 return start_l(); 270} 271 272status_t NuPlayerDriver::start_l() { 273 switch (mState) { 274 case STATE_UNPREPARED: 275 { 276 status_t err = prepare_l(); 277 278 if (err != OK) { 279 return err; 280 } 281 282 CHECK_EQ(mState, STATE_PREPARED); 283 284 // fall through 285 } 286 287 case STATE_PAUSED: 288 case STATE_STOPPED_AND_PREPARED: 289 case STATE_PREPARED: 290 { 291 mPlayer->start(); 292 293 // fall through 294 } 295 296 case STATE_RUNNING: 297 { 298 if (mAtEOS) { 299 mPlayer->seekToAsync(0); 300 mAtEOS = false; 301 mPositionUs = -1; 302 } 303 break; 304 } 305 306 default: 307 return INVALID_OPERATION; 308 } 309 310 mState = STATE_RUNNING; 311 312 return OK; 313} 314 315status_t NuPlayerDriver::stop() { 316 ALOGD("stop(%p)", this); 317 Mutex::Autolock autoLock(mLock); 318 319 switch (mState) { 320 case STATE_RUNNING: 321 mPlayer->pause(); 322 // fall through 323 324 case STATE_PAUSED: 325 mState = STATE_STOPPED; 326 notifyListener_l(MEDIA_STOPPED); 327 break; 328 329 case STATE_PREPARED: 330 case STATE_STOPPED: 331 case STATE_STOPPED_AND_PREPARING: 332 case STATE_STOPPED_AND_PREPARED: 333 mState = STATE_STOPPED; 334 break; 335 336 default: 337 return INVALID_OPERATION; 338 } 339 340 return OK; 341} 342 343status_t NuPlayerDriver::pause() { 344 ALOGD("pause(%p)", this); 345 // The NuPlayerRenderer may get flushed if pause for long enough, e.g. the pause timeout tear 346 // down for audio offload mode. If that happens, the NuPlayerRenderer will no longer know the 347 // current position. So similar to seekTo, update |mPositionUs| to the pause position by calling 348 // getCurrentPosition here. 349 int unused; 350 getCurrentPosition(&unused); 351 352 Mutex::Autolock autoLock(mLock); 353 354 switch (mState) { 355 case STATE_PAUSED: 356 case STATE_PREPARED: 357 return OK; 358 359 case STATE_RUNNING: 360 mState = STATE_PAUSED; 361 notifyListener_l(MEDIA_PAUSED); 362 mPlayer->pause(); 363 break; 364 365 default: 366 return INVALID_OPERATION; 367 } 368 369 return OK; 370} 371 372bool NuPlayerDriver::isPlaying() { 373 return mState == STATE_RUNNING && !mAtEOS; 374} 375 376status_t NuPlayerDriver::setPlaybackSettings(const AudioPlaybackRate &rate) { 377 status_t err = mPlayer->setPlaybackSettings(rate); 378 if (err == OK) { 379 // try to update position 380 int unused; 381 getCurrentPosition(&unused); 382 Mutex::Autolock autoLock(mLock); 383 if (rate.mSpeed == 0.f && mState == STATE_RUNNING) { 384 mState = STATE_PAUSED; 385 notifyListener_l(MEDIA_PAUSED); 386 } else if (rate.mSpeed != 0.f 387 && (mState == STATE_PAUSED 388 || mState == STATE_STOPPED_AND_PREPARED 389 || mState == STATE_PREPARED)) { 390 err = start_l(); 391 } 392 } 393 return err; 394} 395 396status_t NuPlayerDriver::getPlaybackSettings(AudioPlaybackRate *rate) { 397 return mPlayer->getPlaybackSettings(rate); 398} 399 400status_t NuPlayerDriver::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) { 401 return mPlayer->setSyncSettings(sync, videoFpsHint); 402} 403 404status_t NuPlayerDriver::getSyncSettings(AVSyncSettings *sync, float *videoFps) { 405 return mPlayer->getSyncSettings(sync, videoFps); 406} 407 408status_t NuPlayerDriver::seekTo(int msec, MediaPlayerSeekMode mode) { 409 ALOGD("seekTo(%p) (%d ms, %d) at state %d", this, msec, mode, mState); 410 Mutex::Autolock autoLock(mLock); 411 412 int64_t seekTimeUs = msec * 1000ll; 413 414 switch (mState) { 415 case STATE_PREPARED: 416 case STATE_STOPPED_AND_PREPARED: 417 case STATE_PAUSED: 418 case STATE_RUNNING: 419 { 420 mAtEOS = false; 421 mSeekInProgress = true; 422 // seeks can take a while, so we essentially paused 423 notifyListener_l(MEDIA_PAUSED); 424 mPlayer->seekToAsync(seekTimeUs, mode, true /* needNotify */); 425 break; 426 } 427 428 default: 429 return INVALID_OPERATION; 430 } 431 432 mPositionUs = seekTimeUs; 433 return OK; 434} 435 436status_t NuPlayerDriver::getCurrentPosition(int *msec) { 437 int64_t tempUs = 0; 438 { 439 Mutex::Autolock autoLock(mLock); 440 if (mSeekInProgress || (mState == STATE_PAUSED && !mAtEOS)) { 441 tempUs = (mPositionUs <= 0) ? 0 : mPositionUs; 442 *msec = (int)divRound(tempUs, (int64_t)(1000)); 443 return OK; 444 } 445 } 446 447 status_t ret = mPlayer->getCurrentPosition(&tempUs); 448 449 Mutex::Autolock autoLock(mLock); 450 // We need to check mSeekInProgress here because mPlayer->seekToAsync is an async call, which 451 // means getCurrentPosition can be called before seek is completed. Iow, renderer may return a 452 // position value that's different the seek to position. 453 if (ret != OK) { 454 tempUs = (mPositionUs <= 0) ? 0 : mPositionUs; 455 } else { 456 mPositionUs = tempUs; 457 } 458 *msec = (int)divRound(tempUs, (int64_t)(1000)); 459 return OK; 460} 461 462status_t NuPlayerDriver::getDuration(int *msec) { 463 Mutex::Autolock autoLock(mLock); 464 465 if (mDurationUs < 0) { 466 return UNKNOWN_ERROR; 467 } 468 469 *msec = (mDurationUs + 500ll) / 1000; 470 471 return OK; 472} 473 474void NuPlayerDriver::finalizeMetrics(const char *where) { 475 if (where == NULL) { 476 where = "unknown"; 477 } 478 ALOGD("finalizeMetrics(%p) from %s at state %d", this, where, mState); 479 480 // gather the final stats for this record 481 Vector<sp<AMessage>> trackStats; 482 mPlayer->getStats(&trackStats); 483 484 if (trackStats.size() > 0) { 485 for (size_t i = 0; i < trackStats.size(); ++i) { 486 const sp<AMessage> &stats = trackStats.itemAt(i); 487 488 AString mime; 489 stats->findString("mime", &mime); 490 491 AString name; 492 stats->findString("component-name", &name); 493 494 if (mime.startsWith("video/")) { 495 int32_t width, height; 496 mAnalyticsItem->setCString("video/mime", mime.c_str()); 497 if (!name.empty()) { 498 mAnalyticsItem->setCString("video/codec", name.c_str()); 499 } 500 501 if (stats->findInt32("width", &width) 502 && stats->findInt32("height", &height)) { 503 mAnalyticsItem->setInt32("wid", width); 504 mAnalyticsItem->setInt32("ht", height); 505 } 506 507 int64_t numFramesTotal = 0; 508 int64_t numFramesDropped = 0; 509 stats->findInt64("frames-total", &numFramesTotal); 510 stats->findInt64("frames-dropped-output", &numFramesDropped); 511 512 mAnalyticsItem->setInt64("frames", numFramesTotal); 513 mAnalyticsItem->setInt64("dropped", numFramesDropped); 514 515 516 } else if (mime.startsWith("audio/")) { 517 mAnalyticsItem->setCString("audio/mime", mime.c_str()); 518 if (!name.empty()) { 519 mAnalyticsItem->setCString("audio/codec", name.c_str()); 520 } 521 } 522 } 523 524 // getDuration() uses mLock for mutex -- careful where we use it. 525 int duration_ms = -1; 526 getDuration(&duration_ms); 527 if (duration_ms != -1) { 528 mAnalyticsItem->setInt64("duration", duration_ms); 529 } 530 531 if (mPlayingTimeUs > 0) { 532 mAnalyticsItem->setInt64("playing", (mPlayingTimeUs+500)/1000 ); 533 } 534 } 535} 536 537 538void NuPlayerDriver::logMetrics(const char *where) { 539 if (where == NULL) { 540 where = "unknown"; 541 } 542 ALOGD("logMetrics(%p) from %s at state %d", this, where, mState); 543 544 if (mAnalyticsItem == NULL || mAnalyticsItem->isEnabled() == false) { 545 return; 546 } 547 548 // only bother to log non-empty records 549 if (mAnalyticsItem->count() > 0) { 550 551 mAnalyticsItem->setFinalized(true); 552 mAnalyticsItem->selfrecord(); 553 554 // re-init in case we prepare() and start() again. 555 delete mAnalyticsItem ; 556 mAnalyticsItem = new MediaAnalyticsItem("nuplayer"); 557 if (mAnalyticsItem) { 558 mAnalyticsItem->generateSessionID(); 559 } 560 } else { 561 ALOGV("did not have anything to record"); 562 } 563} 564 565status_t NuPlayerDriver::reset() { 566 ALOGD("reset(%p) at state %d", this, mState); 567 568 finalizeMetrics("reset"); 569 logMetrics("reset"); 570 571 Mutex::Autolock autoLock(mLock); 572 573 switch (mState) { 574 case STATE_IDLE: 575 return OK; 576 577 case STATE_SET_DATASOURCE_PENDING: 578 case STATE_RESET_IN_PROGRESS: 579 return INVALID_OPERATION; 580 581 case STATE_PREPARING: 582 { 583 CHECK(mIsAsyncPrepare); 584 585 notifyListener_l(MEDIA_PREPARED); 586 break; 587 } 588 589 default: 590 break; 591 } 592 593 if (mState != STATE_STOPPED) { 594 notifyListener_l(MEDIA_STOPPED); 595 } 596 597 if (property_get_bool("persist.debug.sf.stats", false)) { 598 Vector<String16> args; 599 dump(-1, args); 600 } 601 602 mState = STATE_RESET_IN_PROGRESS; 603 mPlayer->resetAsync(); 604 605 while (mState == STATE_RESET_IN_PROGRESS) { 606 mCondition.wait(mLock); 607 } 608 609 mDurationUs = -1; 610 mPositionUs = -1; 611 mLooping = false; 612 mPlayingTimeUs = 0; 613 614 return OK; 615} 616 617status_t NuPlayerDriver::setLooping(int loop) { 618 mLooping = loop != 0; 619 return OK; 620} 621 622player_type NuPlayerDriver::playerType() { 623 return NU_PLAYER; 624} 625 626status_t NuPlayerDriver::invoke(const Parcel &request, Parcel *reply) { 627 if (reply == NULL) { 628 ALOGE("reply is a NULL pointer"); 629 return BAD_VALUE; 630 } 631 632 int32_t methodId; 633 status_t ret = request.readInt32(&methodId); 634 if (ret != OK) { 635 ALOGE("Failed to retrieve the requested method to invoke"); 636 return ret; 637 } 638 639 switch (methodId) { 640 case INVOKE_ID_SET_VIDEO_SCALING_MODE: 641 { 642 int mode = request.readInt32(); 643 return mPlayer->setVideoScalingMode(mode); 644 } 645 646 case INVOKE_ID_GET_TRACK_INFO: 647 { 648 return mPlayer->getTrackInfo(reply); 649 } 650 651 case INVOKE_ID_SELECT_TRACK: 652 { 653 int trackIndex = request.readInt32(); 654 int msec = 0; 655 // getCurrentPosition should always return OK 656 getCurrentPosition(&msec); 657 return mPlayer->selectTrack(trackIndex, true /* select */, msec * 1000ll); 658 } 659 660 case INVOKE_ID_UNSELECT_TRACK: 661 { 662 int trackIndex = request.readInt32(); 663 return mPlayer->selectTrack(trackIndex, false /* select */, 0xdeadbeef /* not used */); 664 } 665 666 case INVOKE_ID_GET_SELECTED_TRACK: 667 { 668 int32_t type = request.readInt32(); 669 return mPlayer->getSelectedTrack(type, reply); 670 } 671 672 default: 673 { 674 return INVALID_OPERATION; 675 } 676 } 677} 678 679void NuPlayerDriver::setAudioSink(const sp<AudioSink> &audioSink) { 680 mPlayer->setAudioSink(audioSink); 681 mAudioSink = audioSink; 682} 683 684status_t NuPlayerDriver::setParameter( 685 int /* key */, const Parcel & /* request */) { 686 return INVALID_OPERATION; 687} 688 689status_t NuPlayerDriver::getParameter(int /* key */, Parcel * /* reply */) { 690 return INVALID_OPERATION; 691} 692 693status_t NuPlayerDriver::getMetadata( 694 const media::Metadata::Filter& /* ids */, Parcel *records) { 695 Mutex::Autolock autoLock(mLock); 696 697 using media::Metadata; 698 699 Metadata meta(records); 700 701 meta.appendBool( 702 Metadata::kPauseAvailable, 703 mPlayerFlags & NuPlayer::Source::FLAG_CAN_PAUSE); 704 705 meta.appendBool( 706 Metadata::kSeekBackwardAvailable, 707 mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_BACKWARD); 708 709 meta.appendBool( 710 Metadata::kSeekForwardAvailable, 711 mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_FORWARD); 712 713 meta.appendBool( 714 Metadata::kSeekAvailable, 715 mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK); 716 717 return OK; 718} 719 720void NuPlayerDriver::notifyResetComplete() { 721 ALOGD("notifyResetComplete(%p)", this); 722 Mutex::Autolock autoLock(mLock); 723 724 CHECK_EQ(mState, STATE_RESET_IN_PROGRESS); 725 mState = STATE_IDLE; 726 mCondition.broadcast(); 727} 728 729void NuPlayerDriver::notifySetSurfaceComplete() { 730 ALOGV("notifySetSurfaceComplete(%p)", this); 731 Mutex::Autolock autoLock(mLock); 732 733 CHECK(mSetSurfaceInProgress); 734 mSetSurfaceInProgress = false; 735 736 mCondition.broadcast(); 737} 738 739void NuPlayerDriver::notifyDuration(int64_t durationUs) { 740 Mutex::Autolock autoLock(mLock); 741 mDurationUs = durationUs; 742} 743 744void NuPlayerDriver::notifyMorePlayingTimeUs(int64_t playingUs) { 745 Mutex::Autolock autoLock(mLock); 746 mPlayingTimeUs += playingUs; 747} 748 749void NuPlayerDriver::notifySeekComplete() { 750 ALOGV("notifySeekComplete(%p)", this); 751 Mutex::Autolock autoLock(mLock); 752 mSeekInProgress = false; 753 notifySeekComplete_l(); 754} 755 756void NuPlayerDriver::notifySeekComplete_l() { 757 bool wasSeeking = true; 758 if (mState == STATE_STOPPED_AND_PREPARING) { 759 wasSeeking = false; 760 mState = STATE_STOPPED_AND_PREPARED; 761 mCondition.broadcast(); 762 if (!mIsAsyncPrepare) { 763 // if we are preparing synchronously, no need to notify listener 764 return; 765 } 766 } else if (mState == STATE_STOPPED) { 767 // no need to notify listener 768 return; 769 } 770 notifyListener_l(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED); 771} 772 773status_t NuPlayerDriver::dump( 774 int fd, const Vector<String16> & /* args */) const { 775 776 Vector<sp<AMessage> > trackStats; 777 mPlayer->getStats(&trackStats); 778 779 AString logString(" NuPlayer\n"); 780 char buf[256] = {0}; 781 782 bool locked = false; 783 for (int i = 0; i < kDumpLockRetries; ++i) { 784 if (mLock.tryLock() == NO_ERROR) { 785 locked = true; 786 break; 787 } 788 usleep(kDumpLockSleepUs); 789 } 790 791 if (locked) { 792 snprintf(buf, sizeof(buf), " state(%d), atEOS(%d), looping(%d), autoLoop(%d)\n", 793 mState, mAtEOS, mLooping, mAutoLoop); 794 mLock.unlock(); 795 } else { 796 snprintf(buf, sizeof(buf), " NPD(%p) lock is taken\n", this); 797 } 798 logString.append(buf); 799 800 for (size_t i = 0; i < trackStats.size(); ++i) { 801 const sp<AMessage> &stats = trackStats.itemAt(i); 802 803 AString mime; 804 if (stats->findString("mime", &mime)) { 805 snprintf(buf, sizeof(buf), " mime(%s)\n", mime.c_str()); 806 logString.append(buf); 807 } 808 809 AString name; 810 if (stats->findString("component-name", &name)) { 811 snprintf(buf, sizeof(buf), " decoder(%s)\n", name.c_str()); 812 logString.append(buf); 813 } 814 815 if (mime.startsWith("video/")) { 816 int32_t width, height; 817 if (stats->findInt32("width", &width) 818 && stats->findInt32("height", &height)) { 819 snprintf(buf, sizeof(buf), " resolution(%d x %d)\n", width, height); 820 logString.append(buf); 821 } 822 823 int64_t numFramesTotal = 0; 824 int64_t numFramesDropped = 0; 825 826 stats->findInt64("frames-total", &numFramesTotal); 827 stats->findInt64("frames-dropped-output", &numFramesDropped); 828 snprintf(buf, sizeof(buf), " numFramesTotal(%lld), numFramesDropped(%lld), " 829 "percentageDropped(%.2f%%)\n", 830 (long long)numFramesTotal, 831 (long long)numFramesDropped, 832 numFramesTotal == 0 833 ? 0.0 : (double)(numFramesDropped * 100) / numFramesTotal); 834 logString.append(buf); 835 } 836 } 837 838 ALOGI("%s", logString.c_str()); 839 840 if (fd >= 0) { 841 FILE *out = fdopen(dup(fd), "w"); 842 fprintf(out, "%s", logString.c_str()); 843 fclose(out); 844 out = NULL; 845 } 846 847 return OK; 848} 849 850void NuPlayerDriver::notifyListener( 851 int msg, int ext1, int ext2, const Parcel *in) { 852 Mutex::Autolock autoLock(mLock); 853 notifyListener_l(msg, ext1, ext2, in); 854} 855 856void NuPlayerDriver::notifyListener_l( 857 int msg, int ext1, int ext2, const Parcel *in) { 858 ALOGD("notifyListener_l(%p), (%d, %d, %d), loop setting(%d, %d)", 859 this, msg, ext1, ext2, mAutoLoop, mLooping); 860 switch (msg) { 861 case MEDIA_PLAYBACK_COMPLETE: 862 { 863 if (mState != STATE_RESET_IN_PROGRESS) { 864 if (mAutoLoop) { 865 audio_stream_type_t streamType = AUDIO_STREAM_MUSIC; 866 if (mAudioSink != NULL) { 867 streamType = mAudioSink->getAudioStreamType(); 868 } 869 if (streamType == AUDIO_STREAM_NOTIFICATION) { 870 ALOGW("disabling auto-loop for notification"); 871 mAutoLoop = false; 872 } 873 } 874 if (mLooping || mAutoLoop) { 875 mPlayer->seekToAsync(0); 876 if (mAudioSink != NULL) { 877 // The renderer has stopped the sink at the end in order to play out 878 // the last little bit of audio. If we're looping, we need to restart it. 879 mAudioSink->start(); 880 } 881 // don't send completion event when looping 882 return; 883 } 884 885 mPlayer->pause(); 886 mState = STATE_PAUSED; 887 } 888 // fall through 889 } 890 891 case MEDIA_ERROR: 892 { 893 mAtEOS = true; 894 break; 895 } 896 897 default: 898 break; 899 } 900 901 mLock.unlock(); 902 sendEvent(msg, ext1, ext2, in); 903 mLock.lock(); 904} 905 906void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) { 907 Mutex::Autolock autoLock(mLock); 908 909 CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING); 910 911 mAsyncResult = err; 912 mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE; 913 mCondition.broadcast(); 914} 915 916void NuPlayerDriver::notifyPrepareCompleted(status_t err) { 917 Mutex::Autolock autoLock(mLock); 918 919 if (mState != STATE_PREPARING) { 920 // We were preparing asynchronously when the client called 921 // reset(), we sent a premature "prepared" notification and 922 // then initiated the reset. This notification is stale. 923 CHECK(mState == STATE_RESET_IN_PROGRESS || mState == STATE_IDLE); 924 return; 925 } 926 927 CHECK_EQ(mState, STATE_PREPARING); 928 929 mAsyncResult = err; 930 931 if (err == OK) { 932 // update state before notifying client, so that if client calls back into NuPlayerDriver 933 // in response, NuPlayerDriver has the right state 934 mState = STATE_PREPARED; 935 if (mIsAsyncPrepare) { 936 notifyListener_l(MEDIA_PREPARED); 937 } 938 } else { 939 mState = STATE_UNPREPARED; 940 if (mIsAsyncPrepare) { 941 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); 942 } 943 } 944 945 sp<MetaData> meta = mPlayer->getFileMeta(); 946 int32_t loop; 947 if (meta != NULL 948 && meta->findInt32(kKeyAutoLoop, &loop) && loop != 0) { 949 mAutoLoop = true; 950 } 951 952 mCondition.broadcast(); 953} 954 955void NuPlayerDriver::notifyFlagsChanged(uint32_t flags) { 956 Mutex::Autolock autoLock(mLock); 957 958 mPlayerFlags = flags; 959} 960 961} // namespace android 962