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