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