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